<commit_before>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use std::rc::Rc;
use gl;
use gl::types::*;
use nalgebra::na::{Vec2, Vec3};
use text::Font;
use camera::Camera;
use resource::{Shader, ShaderUniform, ShaderAttribute, GPUVector, ArrayBuffer, StreamDraw};

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    color: Vec3<f32>,
    font:  Rc<Font>,
    begin: uint,
    size:  uint
}

impl TextRenderContext {
    pub fn new(color: Vec3<f32>, font: Rc<Font>, begin: uint, size: uint) -> TextRenderContext {
        TextRenderContext {
            color:   color,
            font:    font,
            begin:   begin,
            size:    size
        }
    }
}

/// A ttf text renderer.
pub struct TextRenderer {
    shader:   Shader,
    invsz:    ShaderUniform<Vec2<f32>>,
    tex:      ShaderUniform<GLint>,
    color:    ShaderUniform<Vec3<f32>>,
    pos:      ShaderAttribute<Vec2<f32>>,
    uvs:      ShaderAttribute<Vec2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords:   GPUVector<Vec2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        let mut shader = Shader::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);

        shader.use_program();

        TextRenderer {
            invsz:    shader.get_uniform("invsz").expect("Could not find invsz"),
            tex:      shader.get_uniform("tex0").expect("Could not find tex0"),
            color:    shader.get_uniform("color").expect("Could not find color"),
            pos:      shader.get_attrib("pos").expect("Could not find pos"),
            uvs:      shader.get_attrib("uvs").expect("Could not find uvs"),
            shader:   shader,
            contexts: Vec::new(),
            coords:   GPUVector::new(Vec::new(), ArrayBuffer, StreamDraw)
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(&mut self, text: &str, pos: &Vec2<f32>, font: &Rc<Font>, color: &Vec3<f32>) {
        for coords in self.coords.data_mut().mut_iter() {
            let begin = coords.len();

            for (line_count, line) in text.lines_any().enumerate() {
                let mut temp_pos = pos.clone();
                temp_pos.y       = temp_pos.y + (font.height() as uint * (line_count + 1)) as f32;

                for curr in line.chars() {
                    // XXX: do _not_ use a hashmap!
                    let glyph = match font.glyphs()[curr as uint] {
                        Some(ref g) => g,
                        None        => continue,
                    };

                    let end_x = temp_pos.x + glyph.offset.x;
                    let end_y = -temp_pos.y - (glyph.dimensions.y - glyph.offset.y);
                    let end_w = glyph.dimensions.x;
                    let end_h = glyph.dimensions.y;

                    temp_pos.x = temp_pos.x + glyph.advance.x;
                    temp_pos.y = temp_pos.y + glyph.advance.y;

                    // Skip empty glyphs.
                    if end_w <= 0.1 || end_h <= 0.1 {
                        continue;
                    }

                    let adimx = font.atlas_dimensions().x as f32;
                    let adimy = font.atlas_dimensions().y as f32;

                    coords.push(Vec2::new(end_x, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y));

                    coords.push(Vec2::new(end_x, -end_y));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x + end_w, -end_y));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y));

                    coords.push(Vec2::new(end_x + end_w, -end_y));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x + end_w, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y));
                }
            }

            let size = coords.len() - begin;

            if size > 0 {
                self.contexts.push(TextRenderContext::new(color.clone(), font.clone(), begin, size));
            }
        }
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.coords.len() == 0 { return }

        self.shader.use_program();

        verify!(gl::Enable(gl::BLEND));
        verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
        verify!(gl::Disable(gl::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vec2::new(1.0 / width, -1.0 / height));

        for ctxt in self.contexts.iter() {
            verify!(gl::BindTexture(gl::TEXTURE_2D, ctxt.font.texture_atlas()));
            verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32));
            verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32));

            self.pos.bind_sub_buffer(&mut self.coords, 1, ctxt.begin + 0);
            self.uvs.bind_sub_buffer(&mut self.coords, 1, ctxt.begin + 1);
            self.color.upload(&ctxt.color);

            verify!(gl::DrawArrays(gl::TRIANGLES, 0, (ctxt.size / 2) as i32));
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(gl::Enable(gl::DEPTH_TEST));
        verify!(gl::Disable(gl::BLEND));

        for coords in self.coords.data_mut().mut_iter() {
            coords.clear()
        }

        self.contexts.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC:   &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

static A_VERY_LONG_STRING: &'static str =
"
#version 120

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

static ANOTHER_VERY_LONG_STRING: &'static str =
"
#version 120

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<commit_msg>Make the text renderer switch to polygon fill mode.<commit_after>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use std::rc::Rc;
use gl;
use gl::types::*;
use nalgebra::na::{Vec2, Vec3};
use text::Font;
use camera::Camera;
use resource::{Shader, ShaderUniform, ShaderAttribute, GPUVector, ArrayBuffer, StreamDraw};

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    color: Vec3<f32>,
    font:  Rc<Font>,
    begin: uint,
    size:  uint
}

impl TextRenderContext {
    pub fn new(color: Vec3<f32>, font: Rc<Font>, begin: uint, size: uint) -> TextRenderContext {
        TextRenderContext {
            color:   color,
            font:    font,
            begin:   begin,
            size:    size
        }
    }
}

/// A ttf text renderer.
pub struct TextRenderer {
    shader:   Shader,
    invsz:    ShaderUniform<Vec2<f32>>,
    tex:      ShaderUniform<GLint>,
    color:    ShaderUniform<Vec3<f32>>,
    pos:      ShaderAttribute<Vec2<f32>>,
    uvs:      ShaderAttribute<Vec2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords:   GPUVector<Vec2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        let mut shader = Shader::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);

        shader.use_program();

        TextRenderer {
            invsz:    shader.get_uniform("invsz").expect("Could not find invsz"),
            tex:      shader.get_uniform("tex0").expect("Could not find tex0"),
            color:    shader.get_uniform("color").expect("Could not find color"),
            pos:      shader.get_attrib("pos").expect("Could not find pos"),
            uvs:      shader.get_attrib("uvs").expect("Could not find uvs"),
            shader:   shader,
            contexts: Vec::new(),
            coords:   GPUVector::new(Vec::new(), ArrayBuffer, StreamDraw)
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(&mut self, text: &str, pos: &Vec2<f32>, font: &Rc<Font>, color: &Vec3<f32>) {
        for coords in self.coords.data_mut().mut_iter() {
            let begin = coords.len();

            for (line_count, line) in text.lines_any().enumerate() {
                let mut temp_pos = pos.clone();
                temp_pos.y       = temp_pos.y + (font.height() as uint * (line_count + 1)) as f32;

                for curr in line.chars() {
                    // XXX: do _not_ use a hashmap!
                    let glyph = match font.glyphs()[curr as uint] {
                        Some(ref g) => g,
                        None        => continue,
                    };

                    let end_x = temp_pos.x + glyph.offset.x;
                    let end_y = -temp_pos.y - (glyph.dimensions.y - glyph.offset.y);
                    let end_w = glyph.dimensions.x;
                    let end_h = glyph.dimensions.y;

                    temp_pos.x = temp_pos.x + glyph.advance.x;
                    temp_pos.y = temp_pos.y + glyph.advance.y;

                    // Skip empty glyphs.
                    if end_w <= 0.1 || end_h <= 0.1 {
                        continue;
                    }

                    let adimx = font.atlas_dimensions().x as f32;
                    let adimy = font.atlas_dimensions().y as f32;

                    coords.push(Vec2::new(end_x, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y));

                    coords.push(Vec2::new(end_x, -end_y));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x + end_w, -end_y));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x, glyph.tex.y));

                    coords.push(Vec2::new(end_x + end_w, -end_y));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y + (end_h / adimy)));

                    coords.push(Vec2::new(end_x + end_w, -end_y - end_h));
                    coords.push(Vec2::new(glyph.tex.x + (end_w / adimx), glyph.tex.y));
                }
            }

            let size = coords.len() - begin;

            if size > 0 {
                self.contexts.push(TextRenderContext::new(color.clone(), font.clone(), begin, size));
            }
        }
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.coords.len() == 0 { return }

        self.shader.use_program();

        verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL));
        verify!(gl::Enable(gl::BLEND));
        verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
        verify!(gl::Disable(gl::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vec2::new(1.0 / width, -1.0 / height));

        for ctxt in self.contexts.iter() {
            verify!(gl::BindTexture(gl::TEXTURE_2D, ctxt.font.texture_atlas()));
            verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32));
            verify!(gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32));

            self.pos.bind_sub_buffer(&mut self.coords, 1, ctxt.begin + 0);
            self.uvs.bind_sub_buffer(&mut self.coords, 1, ctxt.begin + 1);
            self.color.upload(&ctxt.color);

            verify!(gl::DrawArrays(gl::TRIANGLES, 0, (ctxt.size / 2) as i32));
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(gl::Enable(gl::DEPTH_TEST));
        verify!(gl::Disable(gl::BLEND));

        for coords in self.coords.data_mut().mut_iter() {
            coords.clear()
        }

        self.contexts.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC:   &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

static A_VERY_LONG_STRING: &'static str =
"
#version 120

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

static ANOTHER_VERY_LONG_STRING: &'static str =
"
#version 120

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_export]
macro_rules! executable(
    () => ({
        let module = module_path!();
        if &module[0..3] == "uu_" {
            &module[3..]
        } else {
            module
        }
    })
);

#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: error: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: warning: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! show_info(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! disp_err(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
        pipe_writeln!(&mut ::std::io::stderr(), "Try '{} --help' for more information.", executable!());
    })
);

#[macro_export]
macro_rules! eprint(
    ($($args:tt)+) => (pipe_write!(&mut ::std::io::stderr(), $($args)+))
);

#[macro_export]
macro_rules! eprintln(
    ($($args:tt)+) => (pipe_writeln!(&mut ::std::io::stderr(), $($args)+))
);

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:tt)+) => ({
        show_error!($($args)+);
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f),
        }
    )
);

#[macro_export]
macro_rules! pipe_crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(_) => (),
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    ()
                } else {
                    crash!($exitcode, "{}", f)
                }
            },
        }
    )
);

#[macro_export]
macro_rules! return_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                show_error!("{}", f);
                return $exitcode;
            }
        }
    )
);

// XXX: should the pipe_* macros return an Err just to show the write failed?

#[macro_export]
macro_rules! pipe_print(
    ($($args:tt)+) => (
        match write!(&mut ::std::io::stdout(), $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_println(
    ($($args:tt)+) => (
        match writeln!(&mut ::std::io::stdout(), $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_flush(
    () => (
        match ::std::io::stdout().flush() {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    );
    ($fd:expr) => (
        match $fd.flush() {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : general

#[macro_export]
macro_rules! snippet_list_join_oxford {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_inner!($conjunction, $valTwo $(, $remainingVals)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join_or {
    ($valOne:expr, $valTwo:expr) => (
        format!("{} or {}", $valOne, $valTwo)
    );
    ($valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford!("or", $valTwo $(, $remainingVals)*))
    );
}

//-- message templates : help and version

#[macro_export]
macro_rules! msg_version {
    () => (
        format!("{} {}", executable!(), env!("CARGO_PKG_VERSION"))
    )
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input { ($reason: expr) => (
    format!("invalid input: {}", $reason) ); }

#[macro_export]
macro_rules! snippet_no_file_at_path { ($path:expr) => (
    format!("nonexistent path {}", $path) ); }

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => (
        msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    );
    ($about:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_input!(format!("The '{}' ('{}') option {}", $longflag, $shortflag, $about))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => (
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    );
    ($clause:expr, $longflag:expr, $shortflag:expr) => (
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $longflag, $shortflag)
    );
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => (
        msg_invalid_opt_use!(format!("expects {}, but was provided {}", $expects, $received), $flag)
    );
    ($expects:expr, $received:expr, $longflag:expr, $shortflag:expr) => (
        msg_invalid_opt_use!(format!("expects {}, but was provided {}", $expects, $received), $longflag, $shortflag)
    );
}

// -- message templates : invalid input : args

#[macro_export]
macro_rules! msg_arg_invalid_value { ($expects:expr, $received:expr) => (
    msg_invalid_input!(format!("expects its argument to be {}, but was provided {}", $expects, $received)) ); }

#[macro_export]
macro_rules! msg_args_invalid_value { ($expects:expr, $received:expr) => (
    msg_invalid_input!(format!("expects its arguments to be {}, but was provided {}", $expects, $received)) ); }

#[macro_export]
macro_rules! msg_args_nonexistent_file { ($received:expr) => (
    msg_args_invalid_value!("paths to files", snippet_no_file_at_path!($received)));}

#[macro_export]
macro_rules! msg_wrong_number_of_arguments { ($received:expr) => (
    msg_args_invalid_value!("wrong number of arguments") ); }

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects no more than one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*))) ;
    );
}
<commit_msg>coreopts: fix error when using `msg_wrong_number_of_arguments` macro<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[macro_export]
macro_rules! executable(
    () => ({
        let module = module_path!();
        if &module[0..3] == "uu_" {
            &module[3..]
        } else {
            module
        }
    })
);

#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: error: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: warning: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! show_info(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
    })
);

#[macro_export]
macro_rules! disp_err(
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: ", executable!());
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
        pipe_writeln!(&mut ::std::io::stderr(), "Try '{} --help' for more information.", executable!());
    })
);

#[macro_export]
macro_rules! eprint(
    ($($args:tt)+) => (pipe_write!(&mut ::std::io::stderr(), $($args)+))
);

#[macro_export]
macro_rules! eprintln(
    ($($args:tt)+) => (pipe_writeln!(&mut ::std::io::stderr(), $($args)+))
);

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:tt)+) => ({
        show_error!($($args)+);
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f),
        }
    )
);

#[macro_export]
macro_rules! pipe_crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(_) => (),
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    ()
                } else {
                    crash!($exitcode, "{}", f)
                }
            },
        }
    )
);

#[macro_export]
macro_rules! return_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                show_error!("{}", f);
                return $exitcode;
            }
        }
    )
);

// XXX: should the pipe_* macros return an Err just to show the write failed?

#[macro_export]
macro_rules! pipe_print(
    ($($args:tt)+) => (
        match write!(&mut ::std::io::stdout(), $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_println(
    ($($args:tt)+) => (
        match writeln!(&mut ::std::io::stdout(), $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! pipe_flush(
    () => (
        match ::std::io::stdout().flush() {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    );
    ($fd:expr) => (
        match $fd.flush() {
            Ok(_) => true,
            Err(f) => {
                if f.kind() == ::std::io::ErrorKind::BrokenPipe {
                    false
                } else {
                    panic!("{}", f)
                }
            }
        }
    )
);

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : general

#[macro_export]
macro_rules! snippet_list_join_oxford {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_inner!($conjunction, $valTwo $(, $remainingVals)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join_or {
    ($valOne:expr, $valTwo:expr) => (
        format!("{} or {}", $valOne, $valTwo)
    );
    ($valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford!("or", $valTwo $(, $remainingVals)*))
    );
}

//-- message templates : help and version

#[macro_export]
macro_rules! msg_version {
    () => (
        format!("{} {}", executable!(), env!("CARGO_PKG_VERSION"))
    )
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input { ($reason: expr) => (
    format!("invalid input: {}", $reason) ); }

#[macro_export]
macro_rules! snippet_no_file_at_path { ($path:expr) => (
    format!("nonexistent path {}", $path) ); }

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => (
        msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    );
    ($about:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_input!(format!("The '{}' ('{}') option {}", $longflag, $shortflag, $about))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => (
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    );
    ($clause:expr, $longflag:expr, $shortflag:expr) => (
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $longflag, $shortflag)
    );
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => (
        msg_invalid_opt_use!(format!("expects {}, but was provided {}", $expects, $received), $flag)
    );
    ($expects:expr, $received:expr, $longflag:expr, $shortflag:expr) => (
        msg_invalid_opt_use!(format!("expects {}, but was provided {}", $expects, $received), $longflag, $shortflag)
    );
}

// -- message templates : invalid input : args

#[macro_export]
macro_rules! msg_arg_invalid_value { ($expects:expr, $received:expr) => (
    msg_invalid_input!(format!("expects its argument to be {}, but was provided {}", $expects, $received)) ); }

#[macro_export]
macro_rules! msg_args_invalid_value {
    ($expects:expr, $received:expr) => (
        msg_invalid_input!(format!("expects its arguments to be {}, but was provided {}", $expects, $received))
    );
    ($msg:expr) => (
        msg_invalid_input!($msg)
    );
}

#[macro_export]
macro_rules! msg_args_nonexistent_file { ($received:expr) => (
    msg_args_invalid_value!("paths to files", snippet_no_file_at_path!($received)));}

#[macro_export]
macro_rules! msg_wrong_number_of_arguments { () => (
    msg_args_invalid_value!("wrong number of arguments") ); }

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects no more than one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*))) ;
    );
}
<|endoftext|>


<commit_before>macro_rules! e { ($e:expr) => { $e } }

macro_rules! sum {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { $x + sum!($($y),+) }
}

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }

        impl<N> Mul<N> for $ty<N>
        where N: Numeric + Mul<Output = N>
            , N: Copy {

            type Output = Self;
            fn mul(self, rhs: N) -> Self {
                $ty { $($sub: self.$sub * rhs),+ }
            }

        }

        impl<'a, N> Mul<$ty<N>> for $ty<N>
        where N: Numeric
            , N: Mul<Output = N> + Add<Output = N>
            , N: Copy
            , N: Add<&'a N>
            , N: 'a {

            type Output = N;
            fn mul(self, rhs: Self) -> N {
                sum!( $(self.$sub * rhs.$sub),+ )
            }
        }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vector
        impl<N> $name<$ty<N>> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Numeric
            , N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Numeric
            , N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Numeric
            , N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}

macro_rules! impl_converts {
    ($($v: ident, $c: expr),+) => { $(
        impl<N> convert::AsRef<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_ref(&self) -> &[N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [N; $c]> for &'a $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a [N; $c]) -> &'a $v<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [N; $c]> for &'a mut $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a mut [N; $c]) -> &'a mut $v<N> {
                unsafe { transmute(a) }
            }
        }
        // impl<N: ?Sized> From<[N; $c]> for $v<N>
        // where N: Numeric
        //     , N: Copy {
        //     #[inline]
        //     fn from(a: [N; $c]) -> $v<N> {
        //         unsafe { transmute(a) }
        //     }
        // }
    )+}
}
<commit_msg>[vector] Add parallel scalar mult to macros<commit_after>macro_rules! e { ($e:expr) => { $e } }

macro_rules! sum {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { $x + sum!($($y),+) }
}

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }

        #[cfg(features = "parallel")]
        impl<N> Mul<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + Mul<Output = N> {

            type Output = Self;
            fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
        }

        impl<N> Mul<N> for $ty<N>
        where N: Numeric + Mul<Output = N>
            , N: Copy {

            type Output = Self;
            fn mul(self, rhs: N) -> Self {
                $ty { $($sub: self.$sub * rhs),+ }
            }

        }

        impl<N> Mul<$ty<N>> for $ty<N>
        where N: Numeric
            , N: Mul<Output = N> + Add<Output = N>
            , N: Copy {

            type Output = N;
            fn mul(self, rhs: Self) -> N {
                sum!( $(self.$sub * rhs.$sub),+ )
            }
        }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vector
        impl<N> $name<$ty<N>> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Numeric
            , N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Numeric
            , N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Numeric
            , N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}

macro_rules! impl_converts {
    ($($v: ident, $c: expr),+) => { $(
        impl<N> convert::AsRef<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_ref(&self) -> &[N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [N; $c]> for &'a $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a [N; $c]) -> &'a $v<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [N; $c]> for &'a mut $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a mut [N; $c]) -> &'a mut $v<N> {
                unsafe { transmute(a) }
            }
        }
        // impl<N: ?Sized> From<[N; $c]> for $v<N>
        // where N: Numeric
        //     , N: Copy {
        //     #[inline]
        //     fn from(a: [N; $c]) -> $v<N> {
        //         unsafe { transmute(a) }
        //     }
        // }
    )+}
}
<|endoftext|>


<commit_before>use acls::*;
use consts::{CreateMode, ZkError};
use zookeeper::{ZkResult, ZooKeeper};

pub trait ZooKeeperExt {
    fn ensure_path(&self, path: &str) -> ZkResult<()>;
}

impl ZooKeeperExt for ZooKeeper {
    fn ensure_path(&self, path: &str) -> ZkResult<()> {
        for (i, _) in path.chars().enumerate().skip(1).filter(|c| c.1 == '/') {
            match self.create(&path[..i], vec![], OPEN_ACL_UNSAFE.clone(), CreateMode::Persistent) {
                Ok(_) | Err(ZkError::NodeExists) => {},
                Err(e) => return Err(e)
            }
        }
        Ok(())
    }
}
<commit_msg>Fix ensure_path<commit_after>use acls::*;
use consts::{CreateMode, ZkError};
use zookeeper::{ZkResult, ZooKeeper};
use std::iter::once;

pub trait ZooKeeperExt {
    fn ensure_path(&self, path: &str) -> ZkResult<()>;
}

impl ZooKeeperExt for ZooKeeper {
    fn ensure_path(&self, path: &str) -> ZkResult<()> {
        for (i, _) in path.chars().chain(once('/')).enumerate().skip(1).filter(|c| c.1 == '/') {
            match self.create(&path[..i], vec![], OPEN_ACL_UNSAFE.clone(), CreateMode::Persistent) {
                Ok(_) | Err(ZkError::NodeExists) => {},
                Err(e) => return Err(e)
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::{
    executor::Executor, message::Delivery, types::ShortString, wait::NotifyReady, BasicProperties,
    Error,
};
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{collections::VecDeque, fmt, sync::Arc};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: Delivery);
    fn drop_prefetched_messages(&self) {}
    fn on_canceled(&self) {}
    fn on_error(&self, _error: Error) {}
}

#[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(&self, delegate: Box<dyn ConsumerDelegate>) {
        let mut inner = self.inner();
        for delivery in inner.deliveries.drain(..) {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Mutex::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<(), Error> {
        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<(), Error> {
        self.inner().drop_prefetched_messages()
    }

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

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

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries: VecDeque<Delivery>,
    task: Option<Box<dyn NotifyReady + Send>>,
    canceled: bool,
    tag: ShortString,
    delegate: Option<Arc<Mutex<Box<dyn ConsumerDelegate>>>>,
    executor: Arc<dyn Executor>,
    error: Option<Error>,
}

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 {
        Self {
            current_message: None,
            deliveries: VecDeque::new(),
            task: None,
            canceled: false,
            tag: consumer_tag,
            delegate: None,
            executor,
            error: None,
        }
    }

    pub fn next_delivery(&mut self) -> Option<Delivery> {
        self.deliveries.pop_front()
    }

    pub fn set_task(&mut self, task: Box<dyn NotifyReady + Send>) {
        self.task = Some(task);
    }

    pub fn has_task(&self) -> bool {
        self.task.is_some()
    }

    pub fn canceled(&self) -> bool {
        self.canceled
    }

    pub fn error(&mut self) -> Option<Error> {
        self.error.take()
    }

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

    fn new_delivery(&mut self, delivery: Delivery) -> Result<(), Error> {
        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.lock().on_new_delivery(delivery)))?;
        } else {
            self.deliveries.push_back(delivery);
        }
        if let Some(task) = self.task.as_ref() {
            task.notify();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<(), Error> {
        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.lock().drop_prefetched_messages()))?;
        }
        self.deliveries.clear();
        Ok(())
    }

    fn cancel(&mut self) -> Result<(), Error> {
        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.lock().on_canceled()))?;
        }
        self.deliveries.clear();
        self.canceled = true;
        self.task.take();
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<(), Error> {
        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.lock().on_error(error)))?;
        } else {
            self.error = Some(error);
        }
        self.cancel()
    }
}

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

#[cfg(feature = "futures")]
mod futures {
    use super::*;

    use ::futures::stream::Stream;

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

    use crate::confirmation::futures::Watcher;

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

        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()
            );
            if !inner.has_task() {
                inner.set_task(Box::new(Watcher(cx.waker().clone())));
            }
            if let Some(delivery) = inner.next_delivery() {
                trace!(
                    "delivery; consumer_tag={}, delivery_tag={:?}",
                    inner.tag(),
                    delivery.delivery_tag
                );
                Poll::Ready(Some(Ok(delivery)))
            } else if inner.canceled() {
                trace!("consumer canceled; consumer_tag={}", inner.tag());
                if let Some(error) = inner.error() {
                    Poll::Ready(Some(Err(error)))
                } else {
                    Poll::Ready(None)
                }
            } else {
                trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
                Poll::Pending
            }
        }
    }
}
<commit_msg>consumer: switch queue to a channel<commit_after>use crate::{
    executor::Executor, message::Delivery, types::ShortString, wait::NotifyReady, BasicProperties,
    Error,
};
use crossbeam_channel::{Receiver, Sender};
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{fmt, sync::Arc};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: Delivery);
    fn drop_prefetched_messages(&self) {}
    fn on_canceled(&self) {}
    fn on_error(&self, _error: Error) {}
}

#[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(&self, delegate: Box<dyn ConsumerDelegate>) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Mutex::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<(), Error> {
        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<(), Error> {
        self.inner().drop_prefetched_messages()
    }

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

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

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<Delivery>,
    deliveries_out: Receiver<Delivery>,
    task: Option<Box<dyn NotifyReady + Send>>,
    canceled: bool,
    tag: ShortString,
    delegate: Option<Arc<Mutex<Box<dyn ConsumerDelegate>>>>,
    executor: Arc<dyn Executor>,
    error: Option<Error>,
}

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,
            canceled: false,
            tag: consumer_tag,
            delegate: None,
            executor,
            error: None,
        }
    }

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

    pub fn set_task(&mut self, task: Box<dyn NotifyReady + Send>) {
        self.task = Some(task);
    }

    pub fn has_task(&self) -> bool {
        self.task.is_some()
    }

    pub fn canceled(&self) -> bool {
        self.canceled
    }

    pub fn error(&mut self) -> Option<Error> {
        self.error.take()
    }

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

    fn new_delivery(&mut self, delivery: Delivery) -> Result<(), Error> {
        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.lock().on_new_delivery(delivery)))?;
        } else {
            self.deliveries_in
                .send(delivery)
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.notify();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<(), Error> {
        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.lock().drop_prefetched_messages()))?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<(), Error> {
        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.lock().on_canceled()))?;
        }
        while let Some(_) = self.next_delivery() {}
        self.canceled = true;
        self.task.take();
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<(), Error> {
        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.lock().on_error(error)))?;
        } else {
            self.error = Some(error);
        }
        self.cancel()
    }
}

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

#[cfg(feature = "futures")]
mod futures {
    use super::*;

    use ::futures::stream::Stream;

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

    use crate::confirmation::futures::Watcher;

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

        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()
            );
            if !inner.has_task() {
                inner.set_task(Box::new(Watcher(cx.waker().clone())));
            }
            if let Some(delivery) = inner.next_delivery() {
                trace!(
                    "delivery; consumer_tag={}, delivery_tag={:?}",
                    inner.tag(),
                    delivery.delivery_tag
                );
                Poll::Ready(Some(Ok(delivery)))
            } else if inner.canceled() {
                trace!("consumer canceled; consumer_tag={}", inner.tag());
                if let Some(error) = inner.error() {
                    Poll::Ready(Some(Err(error)))
                } else {
                    Poll::Ready(None)
                }
            } else {
                trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
                Poll::Pending
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! FFI interface for Data

use ffi_helpers::Ffi__Array;
use libc::{c_char, c_void, uint8_t};
use serde_json::Value;
use std::ffi::CString;
use std::ptr;
use super::*;

#[repr(C)]
pub enum Ffi__DataType {
    Bool,
    Int64,
    Uint64,
    Float,
    String,
    Array,
    Object,
}

#[no_mangle]
pub extern "C" fn data_open(path_ptr: *const c_char) -> *mut c_void {
    let path = trynull!(ptrtostr!(path_ptr, "path string"));
    let value = trynull!(DataParser::open(path));
    Box::into_raw(Box::new(value)) as *mut c_void
}

#[no_mangle]
pub extern "C" fn get_value(value_ptr: *mut c_void, data_type: Ffi__DataType, pointer_ptr: *const c_char) -> *mut c_void {
    let value: Value = trynull!(readptr!(value_ptr as *mut Value, "Value struct"));
    let pointer = if pointer_ptr.is_null() {
        None
    } else {
        ptrtostr!(pointer_ptr, "").ok()
    };

    match data_type {
        Ffi__DataType::Bool => {
            let b = if let Some(p) = pointer { trynull!(needbool!(value => p)) } else { trynull!(needbool!(value)) };
            Box::into_raw(Box::new(if b { 1u8 } else { 0u8 })) as *mut c_void
        },
        Ffi__DataType::Int64 => {
            let i = if let Some(p) = pointer { trynull!(needi64!(value => p)) } else { trynull!(needi64!(value)) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::Uint64 => {
            let i = if let Some(p) = pointer { trynull!(needu64!(value => p)) } else { trynull!(needu64!(value)) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::Float => {
            let i = if let Some(p) = pointer { trynull!(needf64!(value => p)) } else { trynull!(needf64!(value)) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::String => {
            let s = if let Some(p) = pointer { trynull!(needstr!(value => p)) } else { trynull!(needstr!(value)) };
            trynull!(CString::new(s)).into_raw() as *mut c_void
        },
        Ffi__DataType::Array => {
            let v = if let Some(p) = pointer { trynull!(needarray!(value => p)) } else { trynull!(needarray!(value)) };
            let mut retval = Vec::new();
            for val in v {
                retval.push(val as *const _ as *mut c_void);
            }

            Box::into_raw(Box::new(Ffi__Array::from(retval))) as *mut c_void
        },
        Ffi__DataType::Object => {
            if let Some(p) = pointer {
                if let Some(v) = value.pointer(p) {
                    v as *const _ as *mut c_void
                } else {
                    ptr::null_mut()
                }
            }
            else if value.is_object() {
                value_ptr as *mut c_void
            } else {
                ptr::null_mut()
            }
        }
    }
}

#[no_mangle]
pub extern "C" fn free_value(value_ptr: *mut c_void) -> uint8_t {
    let _: Box<Value> = tryrc!(boxptr!(value_ptr as *mut Value, "Value struct"));
    0
}

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

    #[test]
    fn test_() {

    }
}
<commit_msg>Bug fixes and test for Data FFI<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! FFI interface for Data

use ffi_helpers::Ffi__Array;
use libc::{c_char, c_void, uint8_t};
use serde_json::Value;
use std::ffi::CString;
use std::{mem, ptr};
use super::*;

#[repr(C)]
pub enum Ffi__DataType {
    Bool,
    Int64,
    Uint64,
    Float,
    String,
    Array,
    Object,
}

#[no_mangle]
pub extern "C" fn data_open(path_ptr: *const c_char) -> *mut c_void {
    let path = trynull!(ptrtostr!(path_ptr, "path string"));
    let value = trynull!(DataParser::open(path));
    Box::into_raw(Box::new(value)) as *mut c_void
}

#[no_mangle]
pub extern "C" fn get_value(mut value_ptr: *mut c_void, data_type: Ffi__DataType, pointer_ptr: *const c_char) -> *mut c_void {
    let value: Box<Value> = trynull!(boxptr!(value_ptr as *mut Value, "Value struct"));
    let pointer = if pointer_ptr.is_null() {
        None
    } else {
        ptrtostr!(pointer_ptr, "").ok()
    };

    match data_type {
        Ffi__DataType::Bool => {
            let b = if let Some(p) = pointer { trynull!(needbool!(value => p)) } else { trynull!(needbool!(value)) };
            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            Box::into_raw(Box::new(if b { 1u8 } else { 0u8 })) as *mut c_void
        },
        Ffi__DataType::Int64 => {
            let i = if let Some(p) = pointer { trynull!(needi64!(value => p)) } else { trynull!(needi64!(value)) };
            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::Uint64 => {
            let i = if let Some(p) = pointer { trynull!(needu64!(value => p)) } else { trynull!(needu64!(value)) };
            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::Float => {
            let i = if let Some(p) = pointer { trynull!(needf64!(value => p)) } else { trynull!(needf64!(value)) };
            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            Box::into_raw(Box::new(i)) as *mut c_void
        },
        Ffi__DataType::String => {
            let retval = {
                let s = if let Some(p) = pointer { trynull!(needstr!(value => p)) } else { trynull!(needstr!(value)) };
                trynull!(CString::new(s)).into_raw() as *mut c_void
            };

            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            retval
        },
        Ffi__DataType::Array => {
            let retval = {
                let v = if let Some(p) = pointer { trynull!(needarray!(value => p)) } else { trynull!(needarray!(value)) };
                let mut retval = Vec::new();
                for val in v {
                    retval.push(Box::into_raw(Box::new(val.clone())) as *mut c_void);
                }

                let ffi_a = Ffi__Array::from(retval);
                let retval = &ffi_a as *const _ as *mut c_void;
                mem::forget(ffi_a);
                retval
            };

            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            retval
        },
        Ffi__DataType::Object => {
            let retval = if let Some(p) = pointer {
                if let Some(v) = value.pointer(p) {
                    v as *const _ as *mut c_void
                } else {
                    ptr::null_mut()
                }
            }
            else if value.is_object() {
                value_ptr as *mut c_void
            } else {
                ptr::null_mut()
            };

            unsafe { ptr::write(&mut value_ptr, Box::into_raw(Box::new(value)) as *mut c_void) };
            retval
        }
    }
}

#[no_mangle]
pub extern "C" fn free_value(value_ptr: *mut c_void) -> uint8_t {
    let _: Box<Value> = tryrc!(boxptr!(value_ptr as *mut Value, "Value struct"));
    0
}

#[cfg(test)]
mod tests {
    use ffi_helpers::Ffi__Array;
    use libc::{c_char, c_void};
    use std::ffi::CString;
    use std::fs::File;
    use std::io::Write;
    use std::path::PathBuf;
    use std::ptr;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_open_get_value() {
        let (_td, path) = create_test_data();

        // Test open
        let ps = path.to_str().unwrap();
        let c_path = CString::new(ps).unwrap();
        let value_ptr = data_open(c_path.as_ptr());
        assert!(!value_ptr.is_null());

        // Test bool
        let json_ptr = CString::new("/bool").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::Bool, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let b = unsafe { ptr::read(ptr as *mut bool) };
        assert!(b);

        // Test i64
        let json_ptr = CString::new("/i64").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::Int64, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let i = unsafe { ptr::read(ptr as *mut i64) };
        assert_eq!(i, -5i64);

        // Test u64
        let json_ptr = CString::new("/u64").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::Uint64, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let i = unsafe { ptr::read(ptr as *mut u64) };
        assert_eq!(i, 10u64);

        // Test f64
        let json_ptr = CString::new("/f64").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::Float, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let i = unsafe { ptr::read(ptr as *mut f64) };
        assert_eq!(i, 1.2f64);

        // Test string
        let json_ptr = CString::new("/string").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::String, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let s = ptrtostr!(ptr as *const c_char, "string").unwrap();
        assert_eq!(s, "abc");

        // Test array
        let json_ptr = CString::new("/array").unwrap();
        let ptr = get_value(value_ptr, Ffi__DataType::Array, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let a: Vec<*mut c_void> = readptr!(ptr as *mut Ffi__Array<*mut c_void>, "array").unwrap();
        let mut iter = a.into_iter();

        // Test array int
        let ptr = get_value(iter.next().unwrap(), Ffi__DataType::Uint64, ptr::null());
        assert!(!ptr.is_null());
        let i = unsafe { ptr::read(ptr as *mut u64) };
        assert_eq!(i, 123);

        // Test array string
        let ptr = get_value(iter.next().unwrap(), Ffi__DataType::String, ptr::null());
        let s = ptrtostr!(ptr as *const c_char, "string").unwrap();
        assert_eq!(s, "def");

        // Test object
        let json_ptr = CString::new("/obj").unwrap();
        let o = get_value(value_ptr, Ffi__DataType::Object, json_ptr.as_ptr());
        assert!(!ptr.is_null());

        let json_ptr = CString::new("/a").unwrap();
        let ptr = get_value(o, Ffi__DataType::String, json_ptr.as_ptr());
        assert!(!ptr.is_null());
        let s = ptrtostr!(ptr as *const c_char, "obj string").unwrap();
        assert_eq!(s, "b");
    }

    fn create_test_data() -> (TempDir, PathBuf) {
        let td = TempDir::new("test_data_ffi").unwrap();
        let mut path = td.path().to_owned();
        path.push("data.json");

        let mut fh = File::create(&path).unwrap();
        fh.write_all(b"{
            \"bool\": true,
            \"i64\": -5,
            \"u64\": 10,
            \"f64\": 1.2,
            \"string\": \"abc\",
            \"array\": [
                123,
                \"def\"
            ],
            \"obj\": {
                \"a\": \"b\"
            }
        }").unwrap();

        (td, path)
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use rustc_target::spec::Target;
use std::any::Any;
use std::path::Path;

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {}
    fn provide_extern(&self, providers: &mut Providers) {}

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        use rustc_hir::def_id::LOCAL_CRATE;

        Box::new(CodegenResults {
            crate_name: tcx.crate_name(LOCAL_CRATE),
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            windows_subsystem: None,
            linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<commit_msg>Update hotplug codegen backend test<commit_after>#![feature(rustc_private)]
#![deny(warnings)]

extern crate rustc_codegen_ssa;
extern crate rustc_errors;
extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;

use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
use std::any::Any;

struct TheBackend;

impl CodegenBackend for TheBackend {
    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        _need_metadata_module: bool,
    ) -> Box<dyn Any> {
        Box::new(CodegenResults {
            modules: vec![],
            allocator_module: None,
            metadata_module: None,
            metadata,
            linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
            crate_info: CrateInfo::new(tcx),
        })
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        let codegen_results = ongoing_codegen
            .downcast::<CodegenResults>()
            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
        Ok((*codegen_results, FxHashMap::default()))
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_session::{config::CrateType, output::out_filename};
        use std::io::Write;
        let crate_name = codegen_results.crate_info.local_crate_name;
        for &crate_type in sess.opts.crate_types.iter() {
            if crate_type != CrateType::Rlib {
                sess.fatal(&format!("Crate type is {:?}", crate_type));
            }
            let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
            let mut out_file = ::std::fs::File::create(output_name).unwrap();
            write!(out_file, "This has been \"compiled\" successfully.").unwrap();
        }
        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(TheBackend)
}
<|endoftext|>