<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    display: glium::Display,
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: glium::Display, program: glium::Program) -> Backend {
        Backend {
            display: display,
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(&self.display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in self.display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    match vk {
                        Tab => {
                            context.input_key_state(vitral::Keycode::Tab,
                                                    is_down)
                        }
                        LShift | RShift => {
                            context.input_key_state(vitral::Keycode::Shift,
                                                    is_down)
                        }
                        LControl | RControl => {
                            context.input_key_state(vitral::Keycode::Ctrl,
                                                    is_down)
                        }
                        NumpadEnter | Return => {
                            context.input_key_state(vitral::Keycode::Enter,
                                                    is_down)
                        }
                        Back => {
                            context.input_key_state(vitral::Keycode::Backspace,
                                                    is_down)
                        }
                        Delete => {
                            context.input_key_state(vitral::Keycode::Del,
                                                    is_down)
                        }
                        Numpad8 | Up => {
                            context.input_key_state(vitral::Keycode::Up,
                                                    is_down)
                        }
                        Numpad2 | Down => {
                            context.input_key_state(vitral::Keycode::Down,
                                                    is_down)
                        }
                        Numpad4 | Left => {
                            context.input_key_state(vitral::Keycode::Left,
                                                    is_down)
                        }
                        Numpad6 | Right => {
                            context.input_key_state(vitral::Keycode::Right,
                                                    is_down)
                        }
                        _ => {}
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&self.display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(&self.display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // building the display, ie. the main object
    let program = program!(
        &display,
        150 => {
        vertex: "
            #version 150 core

            uniform mat4 matrix;

            in vec2 pos;
            in vec4 color;
            in vec2 tex;

            out vec4 vColor;
            out vec2 vTexcoord;

            void main() {
                gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                vColor = color;
                vTexcoord = tex;
            }
        ",

        fragment: "
            #version 150 core
            uniform sampler2D tex;
            in vec4 vColor;
            in vec2 vTexcoord;
            out vec4 f_color;

            void main() {
                f_color = vColor * texture(tex, vTexcoord);
            }
        "})
                      .unwrap();

    let mut backend = Backend::new(display, program);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&mut context) {
            return;
        }
    }
}
<commit_msg>Compress the input bit<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    display: glium::Display,
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: glium::Display, program: glium::Program) -> Backend {
        Backend {
            display: display,
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(&self.display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in self.display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    if let Some(vk) = match vk {
                        Tab => Some(vitral::Keycode::Tab),
                        LShift | RShift => Some(vitral::Keycode::Shift),
                        LControl | RControl => Some(vitral::Keycode::Ctrl),
                        NumpadEnter | Return => Some(vitral::Keycode::Enter),
                        Back => Some(vitral::Keycode::Backspace),
                        Delete => Some(vitral::Keycode::Del),
                        Numpad8 | Up => Some(vitral::Keycode::Up),
                        Numpad2 | Down => Some(vitral::Keycode::Down),
                        Numpad4 | Left => Some(vitral::Keycode::Left),
                        Numpad6 | Right => Some(vitral::Keycode::Right),
                        _ => None
                    } {
                        context.input_key_state(vk, is_down);
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&self.display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(&self.display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], texcoord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex: texcoord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    // building the display, ie. the main object
    let program = program!(
        &display,
        150 => {
        vertex: "
            #version 150 core

            uniform mat4 matrix;

            in vec2 pos;
            in vec4 color;
            in vec2 tex;

            out vec4 vColor;
            out vec2 vTexcoord;

            void main() {
                gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                vColor = color;
                vTexcoord = tex;
            }
        ",

        fragment: "
            #version 150 core
            uniform sampler2D tex;
            in vec4 vColor;
            in vec2 vTexcoord;
            out vec4 f_color;

            void main() {
                f_color = vColor * texture(tex, vTexcoord);
            }
        "})
                      .unwrap();

    let mut backend = Backend::new(display, program);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&mut context) {
            return;
        }
    }
}
<|endoftext|>


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

// spell-checker:ignore (ToDO) errno

#[macro_use]
extern crate uucore;

use clap::{crate_version, Arg, Command};
use std::fs;
use std::io::{stdout, Write};
use std::path::{Path, PathBuf};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
use uucore::format_usage;
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};

const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
const USAGE: &str = "{} [OPTION]... [FILE]...";
const OPT_CANONICALIZE: &str = "canonicalize";
const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
const OPT_NO_NEWLINE: &str = "no-newline";
const OPT_QUIET: &str = "quiet";
const OPT_SILENT: &str = "silent";
const OPT_VERBOSE: &str = "verbose";
const OPT_ZERO: &str = "zero";

const ARG_FILES: &str = "files";

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let mut no_trailing_delimiter = matches.contains_id(OPT_NO_NEWLINE);
    let use_zero = matches.contains_id(OPT_ZERO);
    let silent = matches.contains_id(OPT_SILENT) || matches.contains_id(OPT_QUIET);
    let verbose = matches.contains_id(OPT_VERBOSE);

    let res_mode = if matches.contains_id(OPT_CANONICALIZE)
        || matches.contains_id(OPT_CANONICALIZE_EXISTING)
        || matches.contains_id(OPT_CANONICALIZE_MISSING)
    {
        ResolveMode::Logical
    } else {
        ResolveMode::None
    };

    let can_mode = if matches.contains_id(OPT_CANONICALIZE_EXISTING) {
        MissingHandling::Existing
    } else if matches.contains_id(OPT_CANONICALIZE_MISSING) {
        MissingHandling::Missing
    } else {
        MissingHandling::Normal
    };

    let files: Vec<String> = matches
        .get_many::<String>(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();
    if files.is_empty() {
        return Err(UUsageError::new(1, "missing operand"));
    }

    if no_trailing_delimiter && files.len() > 1 && !silent {
        show_error!("ignoring --no-newline with multiple arguments");
        no_trailing_delimiter = false;
    }

    for f in &files {
        let p = PathBuf::from(f);
        let path_result = if res_mode == ResolveMode::None {
            fs::read_link(&p)
        } else {
            canonicalize(&p, can_mode, res_mode)
        };
        match path_result {
            Ok(path) => {
                show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)?
            }
            Err(err) => {
                if verbose {
                    return Err(USimpleError::new(
                        1,
                        err.map_err_context(move || f.maybe_quote().to_string())
                            .to_string(),
                    ));
                } else {
                    return Err(1.into());
                }
            }
        }
    }
    Ok(())
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_help(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(OPT_CANONICALIZE)
                .short('f')
                .long(OPT_CANONICALIZE)
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively; all but the last component must exist",
                ),
        )
        .arg(
            Arg::new(OPT_CANONICALIZE_EXISTING)
                .short('e')
                .long("canonicalize-existing")
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively, all components must exist",
                ),
        )
        .arg(
            Arg::new(OPT_CANONICALIZE_MISSING)
                .short('m')
                .long(OPT_CANONICALIZE_MISSING)
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively, without requirements on components existence",
                ),
        )
        .arg(
            Arg::new(OPT_NO_NEWLINE)
                .short('n')
                .long(OPT_NO_NEWLINE)
                .help("do not output the trailing delimiter"),
        )
        .arg(
            Arg::new(OPT_QUIET)
                .short('q')
                .long(OPT_QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(OPT_SILENT)
                .short('s')
                .long(OPT_SILENT)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(OPT_VERBOSE)
                .short('v')
                .long(OPT_VERBOSE)
                .help("report error message"),
        )
        .arg(
            Arg::new(OPT_ZERO)
                .short('z')
                .long(OPT_ZERO)
                .help("separate output with NUL rather than newline"),
        )
        .arg(
            Arg::new(ARG_FILES)
                .multiple_occurrences(true)
                .takes_value(true)
                .value_hint(clap::ValueHint::AnyPath),
        )
}

fn show(path: &Path, no_trailing_delimiter: bool, use_zero: bool) -> std::io::Result<()> {
    let path = path.to_str().unwrap();
    if no_trailing_delimiter {
        print!("{}", path);
    } else if use_zero {
        print!("{}\0", path);
    } else {
        println!("{}", path);
    }
    stdout().flush()
}
<commit_msg>readlink: follow clippy advice, add semicolon<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Haitao Li <lihaitao@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) errno

#[macro_use]
extern crate uucore;

use clap::{crate_version, Arg, Command};
use std::fs;
use std::io::{stdout, Write};
use std::path::{Path, PathBuf};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
use uucore::format_usage;
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};

const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
const USAGE: &str = "{} [OPTION]... [FILE]...";
const OPT_CANONICALIZE: &str = "canonicalize";
const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
const OPT_NO_NEWLINE: &str = "no-newline";
const OPT_QUIET: &str = "quiet";
const OPT_SILENT: &str = "silent";
const OPT_VERBOSE: &str = "verbose";
const OPT_ZERO: &str = "zero";

const ARG_FILES: &str = "files";

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let mut no_trailing_delimiter = matches.contains_id(OPT_NO_NEWLINE);
    let use_zero = matches.contains_id(OPT_ZERO);
    let silent = matches.contains_id(OPT_SILENT) || matches.contains_id(OPT_QUIET);
    let verbose = matches.contains_id(OPT_VERBOSE);

    let res_mode = if matches.contains_id(OPT_CANONICALIZE)
        || matches.contains_id(OPT_CANONICALIZE_EXISTING)
        || matches.contains_id(OPT_CANONICALIZE_MISSING)
    {
        ResolveMode::Logical
    } else {
        ResolveMode::None
    };

    let can_mode = if matches.contains_id(OPT_CANONICALIZE_EXISTING) {
        MissingHandling::Existing
    } else if matches.contains_id(OPT_CANONICALIZE_MISSING) {
        MissingHandling::Missing
    } else {
        MissingHandling::Normal
    };

    let files: Vec<String> = matches
        .get_many::<String>(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();
    if files.is_empty() {
        return Err(UUsageError::new(1, "missing operand"));
    }

    if no_trailing_delimiter && files.len() > 1 && !silent {
        show_error!("ignoring --no-newline with multiple arguments");
        no_trailing_delimiter = false;
    }

    for f in &files {
        let p = PathBuf::from(f);
        let path_result = if res_mode == ResolveMode::None {
            fs::read_link(&p)
        } else {
            canonicalize(&p, can_mode, res_mode)
        };
        match path_result {
            Ok(path) => {
                show(&path, no_trailing_delimiter, use_zero).map_err_context(String::new)?;
            }
            Err(err) => {
                if verbose {
                    return Err(USimpleError::new(
                        1,
                        err.map_err_context(move || f.maybe_quote().to_string())
                            .to_string(),
                    ));
                } else {
                    return Err(1.into());
                }
            }
        }
    }
    Ok(())
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_help(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(OPT_CANONICALIZE)
                .short('f')
                .long(OPT_CANONICALIZE)
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively; all but the last component must exist",
                ),
        )
        .arg(
            Arg::new(OPT_CANONICALIZE_EXISTING)
                .short('e')
                .long("canonicalize-existing")
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively, all components must exist",
                ),
        )
        .arg(
            Arg::new(OPT_CANONICALIZE_MISSING)
                .short('m')
                .long(OPT_CANONICALIZE_MISSING)
                .help(
                    "canonicalize by following every symlink in every component of the \
                     given name recursively, without requirements on components existence",
                ),
        )
        .arg(
            Arg::new(OPT_NO_NEWLINE)
                .short('n')
                .long(OPT_NO_NEWLINE)
                .help("do not output the trailing delimiter"),
        )
        .arg(
            Arg::new(OPT_QUIET)
                .short('q')
                .long(OPT_QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(OPT_SILENT)
                .short('s')
                .long(OPT_SILENT)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::new(OPT_VERBOSE)
                .short('v')
                .long(OPT_VERBOSE)
                .help("report error message"),
        )
        .arg(
            Arg::new(OPT_ZERO)
                .short('z')
                .long(OPT_ZERO)
                .help("separate output with NUL rather than newline"),
        )
        .arg(
            Arg::new(ARG_FILES)
                .multiple_occurrences(true)
                .takes_value(true)
                .value_hint(clap::ValueHint::AnyPath),
        )
}

fn show(path: &Path, no_trailing_delimiter: bool, use_zero: bool) -> std::io::Result<()> {
    let path = path.to_str().unwrap();
    if no_trailing_delimiter {
        print!("{}", path);
    } else if use_zero {
        print!("{}\0", path);
    } else {
        println!("{}", path);
    }
    stdout().flush()
}
<|endoftext|>


<commit_before>use std::io::Cursor;

use anyhow::{Context, Result};
use async_std::prelude::*;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use log::debug;

use crate::message::*;

pub use crate::platform::socket::*;

/// Convenience wrapper around send_bytes.
/// Deserialize a message and feed the bytes into send_bytes.
pub async fn send_message(message: Message, stream: &mut GenericStream) -> Result<()> {
    debug!("Sending message: {:?}", message);
    // Prepare command for transfer and determine message byte size
    let payload = bincode::serialize(&message).expect("Failed to serialize message.");

    send_bytes(&payload, stream).await
}

/// Send a Vec of bytes. Before the actual bytes are send, the size of the message
/// is transmitted in an header of fixed size (u64).
pub async fn send_bytes(payload: &[u8], stream: &mut GenericStream) -> Result<()> {
    let message_size = payload.len() as u64;

    let mut header = vec![];
    header.write_u64::<BigEndian>(message_size).unwrap();

    // Send the request size header first.
    // Afterwards send the request.
    stream.write_all(&header).await?;

    // Split the payload into 1.5kbyte chunks (MUT for TCP)
    for chunk in payload.chunks(1500) {
        stream.write_all(chunk).await?;
    }

    Ok(())
}

/// Receive a byte stream depending on a given header.
/// This is the basic protocol beneath all pueue communication.
pub async fn receive_bytes(stream: &mut GenericStream) -> Result<Vec<u8>> {
    // Receive the header with the overall message size
    let mut header = vec![0; 8];
    stream.read(&mut header).await?;
    let mut header = Cursor::new(header);
    let message_size = header.read_u64::<BigEndian>()? as usize;

    // Buffer for the whole payload
    let mut payload_bytes = Vec::with_capacity(message_size);

    // Receive chunks until we reached the expected message size
    while payload_bytes.len() < message_size {
        // Calculate the amount of bytes left
        // By default try a buffer size of 1024 bytes
        let mut chunk_size = message_size - payload_bytes.len();
        if chunk_size > 1024 {
            chunk_size = 1024;
        }

        // Read data and get the amount of received bytes
        let mut chunk = vec![0; chunk_size];
        let received_bytes = stream.read(&mut chunk).await?;

        // If we received less bytes than the chunk buffer size,
        // split the unneeded bytes, since they are filled with zeros
        if received_bytes < chunk_size {
            let _ = chunk.split_off(received_bytes);
        }

        payload_bytes.append(&mut chunk);
    }

    Ok(payload_bytes)
}

/// Convenience wrapper that receives a message and converts it into a Message.
pub async fn receive_message(stream: &mut GenericStream) -> Result<Message> {
    let payload_bytes = receive_bytes(stream).await?;
    debug!("Received {} bytes", payload_bytes.len());

    // Deserialize the message.
    let message: Message = bincode::deserialize(&payload_bytes).context(
        "In case you updated Pueue, try restarting the daemon. Otherwise please report this",
    )?;
    debug!("Received message: {:?}", message);

    Ok(message)
}

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

    use async_std::net::{TcpListener, TcpStream};
    use async_std::task;

    #[async_std::test]
    async fn test_single_huge_payload() -> Result<()> {
        let listener = TcpListener::bind("127.0.0.1:0").await?;
        let addr = listener.local_addr()?;

        // The message that should be sent
        let payload = "a".repeat(100_000);
        let message = create_success_message(payload);
        let original_bytes = bincode::serialize(&message).expect("Failed to serialize message.");

        let listener: Box<dyn GenericListener> = Box::new(listener);

        // Spawn a sub thread that:
        // 1. Accepts a new connection
        // 2. Reads a message
        // 3. Sends the same message back
        task::spawn(async move {
            let mut stream = listener.accept().await.unwrap();
            let message_bytes = receive_bytes(&mut stream).await.unwrap();

            let message: Message = bincode::deserialize(&message_bytes).unwrap();

            send_message(message, &mut stream).await.unwrap();
        });

        let mut client: GenericStream = Box::new(TcpStream::connect(&addr).await?);

        // Create a client that sends a message and instantly receives it
        send_message(message, &mut client).await?;
        let response_bytes = receive_bytes(&mut client).await?;
        let _message: Message = bincode::deserialize(&response_bytes)?;

        assert_eq!(response_bytes, original_bytes);

        Ok(())
    }
}
<commit_msg>Fix tests<commit_after>use std::io::Cursor;

use anyhow::{Context, Result};
use async_std::prelude::*;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use log::debug;

use crate::message::*;

pub use crate::platform::socket::*;

/// Convenience wrapper around send_bytes.
/// Deserialize a message and feed the bytes into send_bytes.
pub async fn send_message(message: Message, stream: &mut GenericStream) -> Result<()> {
    debug!("Sending message: {:?}", message);
    // Prepare command for transfer and determine message byte size
    let payload = bincode::serialize(&message).expect("Failed to serialize message.");

    send_bytes(&payload, stream).await
}

/// Send a Vec of bytes. Before the actual bytes are send, the size of the message
/// is transmitted in an header of fixed size (u64).
pub async fn send_bytes(payload: &[u8], stream: &mut GenericStream) -> Result<()> {
    let message_size = payload.len() as u64;

    let mut header = vec![];
    header.write_u64::<BigEndian>(message_size).unwrap();

    // Send the request size header first.
    // Afterwards send the request.
    stream.write_all(&header).await?;

    // Split the payload into 1.5kbyte chunks (MUT for TCP)
    for chunk in payload.chunks(1500) {
        stream.write_all(chunk).await?;
    }

    Ok(())
}

/// Receive a byte stream depending on a given header.
/// This is the basic protocol beneath all pueue communication.
pub async fn receive_bytes(stream: &mut GenericStream) -> Result<Vec<u8>> {
    // Receive the header with the overall message size
    let mut header = vec![0; 8];
    stream.read(&mut header).await?;
    let mut header = Cursor::new(header);
    let message_size = header.read_u64::<BigEndian>()? as usize;

    // Buffer for the whole payload
    let mut payload_bytes = Vec::with_capacity(message_size);

    // Receive chunks until we reached the expected message size
    while payload_bytes.len() < message_size {
        // Calculate the amount of bytes left
        // By default try a buffer size of 1024 bytes
        let mut chunk_size = message_size - payload_bytes.len();
        if chunk_size > 1024 {
            chunk_size = 1024;
        }

        // Read data and get the amount of received bytes
        let mut chunk = vec![0; chunk_size];
        let received_bytes = stream.read(&mut chunk).await?;

        // If we received less bytes than the chunk buffer size,
        // split the unneeded bytes, since they are filled with zeros
        if received_bytes < chunk_size {
            let _ = chunk.split_off(received_bytes);
        }

        payload_bytes.append(&mut chunk);
    }

    Ok(payload_bytes)
}

/// Convenience wrapper that receives a message and converts it into a Message.
pub async fn receive_message(stream: &mut GenericStream) -> Result<Message> {
    let payload_bytes = receive_bytes(stream).await?;
    debug!("Received {} bytes", payload_bytes.len());

    // Deserialize the message.
    let message: Message = bincode::deserialize(&payload_bytes).context(
        "In case you updated Pueue, try restarting the daemon. Otherwise please report this",
    )?;
    debug!("Received message: {:?}", message);

    Ok(message)
}

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

    use async_std::net::{TcpListener, TcpStream};
    use async_std::task;
    use async_trait::async_trait;

    use crate::platform::socket::Stream as PueueStream;

    // Implement generic Listener/Stream traits, so we can test stuff on normal TCP
    #[async_trait]
    impl GenericListener for TcpListener {
        async fn accept<'a>(&'a self) -> Result<GenericStream> {
            let (stream, _) = self.accept().await?;
            Ok(Box::new(stream))
        }
    }
    impl PueueStream for TcpStream {}

    #[async_std::test]
    async fn test_single_huge_payload() -> Result<()> {
        let listener = TcpListener::bind("127.0.0.1:0").await?;
        let addr = listener.local_addr()?;

        // The message that should be sent
        let payload = "a".repeat(100_000);
        let message = create_success_message(payload);
        let original_bytes = bincode::serialize(&message).expect("Failed to serialize message.");

        let listener: Box<dyn GenericListener> = Box::new(listener);

        // Spawn a sub thread that:
        // 1. Accepts a new connection
        // 2. Reads a message
        // 3. Sends the same message back
        task::spawn(async move {
            let mut stream = listener.accept().await.unwrap();
            let message_bytes = receive_bytes(&mut stream).await.unwrap();

            let message: Message = bincode::deserialize(&message_bytes).unwrap();

            send_message(message, &mut stream).await.unwrap();
        });

        let mut client: GenericStream = Box::new(TcpStream::connect(&addr).await?);

        // Create a client that sends a message and instantly receives it
        send_message(message, &mut client).await?;
        let response_bytes = receive_bytes(&mut client).await?;
        let _message: Message = bincode::deserialize(&response_bytes)?;

        assert_eq!(response_bytes, original_bytes);

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;

extern crate time;
extern crate conduit;
extern crate middleware = "conduit-middleware";

use std::fmt::Show;

use conduit::Request;
use middleware::Middleware;

pub struct LogRequests(pub u32);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        match *self {
            LogRequests(level) => log!(level, "{}", log_message(req))
        }
        Ok(())
    }
}

fn log_message(req: &mut Request) -> String {
    format!("{} [{}] {} {}",
            req.remote_ip(),
            time::now().rfc3339(),
            req.method(),
            req.path())
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use super::*;
    use std;
    use log;
    use conduit;
    use middleware;

    use std::io::{ChanWriter, ChanReader};
    use log::{Logger, LogRecord};
    use conduit::{Request, Response, Handler};

    struct MyWriter(ChanWriter);

    impl Logger for MyWriter {
        fn log(&mut self, record: &LogRecord) {
            let MyWriter(ref mut inner) = *self;
            (write!(inner, "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::ERROR));

        task(builder, sender);

        let result = reader.read_to_str().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_str()).collect::<Vec<String>>();

        assert_eq!(parts.get(0).as_slice(), "127.0.0.1");
        assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len());
        assert_eq!(parts.get(2).as_slice(), "Get");
        assert_eq!(parts.get(3).as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        spawn(proc() {
            log::set_logger(box MyWriter(ChanWriter::new(sender)));
            let mut request = test::MockRequest::new(conduit::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, ()> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: box std::io::util::NullReader
        })
    }
}
<commit_msg>Log request timings and response codes<commit_after>#![feature(globs)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;

extern crate time;
extern crate conduit;
extern crate middleware = "conduit-middleware";

use std::any::AnyRefExt;
use std::fmt::Show;

use conduit::{Request, Response};
use middleware::Middleware;

pub struct LogRequests(pub u32);

impl Middleware for LogRequests {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        req.mut_extensions().insert("conduit.log-requests.start",
                                    box time::precise_time_ns());
        Ok(())
    }

    fn after(&self, req: &mut Request,
             resp: Result<Response, Box<Show>>) -> Result<Response, Box<Show>> {
        let start = req.mut_extensions().pop(&"conduit.log-requests.start");
        let start = *start.unwrap().as_ref::<u64>().unwrap();

        match resp {
            Ok(ref resp) => self.log_message(req, start, resp.status.val0(),
                                             None),
            Err(ref e) => {
                let msg: &Show = *e;
                self.log_message(req, start, 500, Some(msg))
            }
        }
        resp
    }

}

impl LogRequests {
    fn log_message(&self, req: &mut Request, start: u64, status: uint,
                   msg: Option<&Show>) {
        let LogRequests(level) = *self;
        log!(level, "{} [{}] {} {} - {}ms {}{}",
             req.remote_ip(),
             time::now().rfc3339(),
             req.method(),
             req.path(),
             (time::precise_time_ns() - start) / 1000000,
             status,
             match msg {
                 None => String::new(),
                 Some(s) => format!(": {}", s),
             })
    }
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use super::*;
    use std;
    use log;
    use conduit;
    use middleware;

    use std::io::{ChanWriter, ChanReader};
    use log::{Logger, LogRecord};
    use conduit::{Request, Response, Handler};

    struct MyWriter(ChanWriter);

    impl Logger for MyWriter {
        fn log(&mut self, record: &LogRecord) {
            let MyWriter(ref mut inner) = *self;
            (write!(inner, "{}", record.args)).unwrap();
        }
    }

    #[test]
    fn test_log() {
        let (sender, receiver) = channel();
        let mut reader = ChanReader::new(receiver);

        let mut builder = middleware::MiddlewareBuilder::new(handler);
        builder.add(LogRequests(log::ERROR));

        task(builder, sender);

        let result = reader.read_to_str().ok().expect("No response");
        let parts = result.as_slice().split(' ').map(|s| s.to_str()).collect::<Vec<String>>();

        assert_eq!(parts.get(0).as_slice(), "127.0.0.1");
        assert!(parts.get(1).as_slice().len() == "[2014-07-01T22:34:06-07:00]".len());
        assert_eq!(parts.get(2).as_slice(), "Get");
        assert_eq!(parts.get(3).as_slice(), "/foo");
    }

    fn task<H: Handler + 'static + Send>(handler: H, sender: Sender<Vec<u8>>) {
        spawn(proc() {
            log::set_logger(box MyWriter(ChanWriter::new(sender)));
            let mut request = test::MockRequest::new(conduit::Get, "/foo");
            let _ = handler.call(&mut request);
        });
    }

    fn handler(_: &mut Request) -> Result<Response, ()> {
        Ok(Response {
            status: (200, "OK"),
            headers: std::collections::HashMap::new(),
            body: box std::io::util::NullReader
        })
    }
}
<|endoftext|>


<commit_before>//! jsonrpc response
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::value::from_value;
use super::{Id, Value, Error, ErrorCode, Version};

/// Successful response
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Success {
	/// Protocol version
    #[serde(skip_serializing_if = "Option::is_none")]
	pub jsonrpc: Option<Version>,
	/// Result
	pub result: Value,
	/// Correlation id
	pub id: Id
}

/// Unsuccessful response
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Failure {
	/// Protocol Version
    #[serde(skip_serializing_if = "Option::is_none")]
	pub jsonrpc: Option<Version>,
	/// Error
	pub error: Error,
	/// Correlation id
	pub id: Id
}

/// Represents output - failure or success
#[derive(Debug, PartialEq, Clone)]
pub enum Output {
	/// Success
	Success(Success),
	/// Failure
	Failure(Failure),
}

impl Output {
	/// Creates new output given `Result`, `Id` and `Version`.
	pub fn from(result: Result<Value, Error>, id: Id, jsonrpc: Option<Version>) -> Self {
		match result {
			Ok(result) => Output::Success(Success {
				id: id,
				jsonrpc: jsonrpc,
				result: result,
			}),
			Err(error) => Output::Failure(Failure {
				id: id,
				jsonrpc: jsonrpc,
				error: error,
			}),
		}
	}

	/// Creates new failure output indicating malformed request.
	pub fn invalid_request(id: Id, jsonrpc: Option<Version>) -> Self {
		Output::Failure(Failure {
			id: id,
			jsonrpc: jsonrpc,
			error: Error::new(ErrorCode::InvalidRequest),
		})
	}
}

impl<'a> Deserialize<'a> for Output {
	fn deserialize<D>(deserializer: D) -> Result<Output, D::Error>
	where D: Deserializer<'a> {
		let v: Value = try!(Deserialize::deserialize(deserializer));
		from_value(v.clone()).map(Output::Failure)
			.or_else(|_| from_value(v).map(Output::Success))
			.map_err(|_| D::Error::custom("")) // types must match
	}
}

impl Serialize for Output {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where S: Serializer {
		match *self {
			Output::Success(ref s) => s.serialize(serializer),
			Output::Failure(ref f) => f.serialize(serializer)
		}
	}
}

/// Synchronous response
#[derive(Debug, PartialEq)]
pub enum Response {
	/// Single response
	Single(Output),
	/// Response to batch request (batch of responses)
	Batch(Vec<Output>)
}

impl<'a> Deserialize<'a> for Response {
	fn deserialize<D>(deserializer: D) -> Result<Response, D::Error>
	where D: Deserializer<'a> {
		let v: Value = try!(Deserialize::deserialize(deserializer));
		from_value(v.clone()).map(Response::Batch)
			.or_else(|_| from_value(v).map(Response::Single))
			.map_err(|_| D::Error::custom("")) // types must match
	}
}

impl Serialize for Response {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where S: Serializer {
		match *self {
			Response::Single(ref o) => o.serialize(serializer),
			Response::Batch(ref b) => b.serialize(serializer)
		}
	}
}

impl Response {
	/// Creates new `Response` with given error and `Version`
	pub fn from(error: Error, jsonrpc: Option<Version>) -> Self {
		Failure {
			id: Id::Null,
			jsonrpc: jsonrpc,
			error: error,
		}.into()
	}
}

impl From<Failure> for Response {
	fn from(failure: Failure) -> Self {
		Response::Single(Output::Failure(failure))
	}
}

impl From<Success> for Response {
	fn from(success: Success) -> Self {
		Response::Single(Output::Success(success))
	}
}

#[test]
fn success_output_serialize() {
	use serde_json;
	use serde_json::Value;

	let so = Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&so).unwrap();
	assert_eq!(serialized, r#"{"jsonrpc":"2.0","result":1,"id":1}"#);
}

#[test]
fn success_output_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dso = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;

	let deserialized: Output = serde_json::from_str(dso).unwrap();
	assert_eq!(deserialized, Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	}));
}

#[test]
fn failure_output_serialize() {
	use serde_json;

	let fo = Output::Failure(Failure {
		jsonrpc: Some(Version::V2),
		error: Error::parse_error(),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&fo).unwrap();
	assert_eq!(serialized, r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#);
}

#[test]
fn failure_output_serialize_jsonrpc_1() {
	use serde_json;

	let fo = Output::Failure(Failure {
		jsonrpc: None,
		error: Error::parse_error(),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&fo).unwrap();
	assert_eq!(serialized, r#"{"error":{"code":-32700,"message":"Parse error"},"id":1}"#);
}

#[test]
fn failure_output_deserialize() {
	use serde_json;

	let dfo = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#;

	let deserialized: Output = serde_json::from_str(dfo).unwrap();
	assert_eq!(deserialized, Output::Failure(Failure {
		jsonrpc: Some(Version::V2),
		error: Error::parse_error(),
		id: Id::Num(1)
	}));
}

#[test]
fn single_response_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dsr = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;

	let deserialized: Response = serde_json::from_str(dsr).unwrap();
	assert_eq!(deserialized, Response::Single(Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	})));
}

#[test]
fn batch_response_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dbr = r#"[{"jsonrpc":"2.0","result":1,"id":1},{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}]"#;

	let deserialized: Response = serde_json::from_str(dbr).unwrap();
	assert_eq!(deserialized, Response::Batch(vec![
		Output::Success(Success {
			jsonrpc: Some(Version::V2),
			result: Value::from(1),
			id: Id::Num(1)
		}),
		Output::Failure(Failure {
			jsonrpc: Some(Version::V2),
			error: Error::parse_error(),
			id: Id::Num(1)
		})
	]));
}
<commit_msg>Add helper methods to Output (#211)<commit_after>//! jsonrpc response
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
use serde_json::value::from_value;
use super::{Id, Value, Error, ErrorCode, Version};

/// Successful response
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Success {
	/// Protocol version
    #[serde(skip_serializing_if = "Option::is_none")]
	pub jsonrpc: Option<Version>,
	/// Result
	pub result: Value,
	/// Correlation id
	pub id: Id
}

/// Unsuccessful response
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Failure {
	/// Protocol Version
    #[serde(skip_serializing_if = "Option::is_none")]
	pub jsonrpc: Option<Version>,
	/// Error
	pub error: Error,
	/// Correlation id
	pub id: Id
}

/// Represents output - failure or success
#[derive(Debug, PartialEq, Clone)]
pub enum Output {
	/// Success
	Success(Success),
	/// Failure
	Failure(Failure),
}

impl Output {
	/// Creates new output given `Result`, `Id` and `Version`.
	pub fn from(result: Result<Value, Error>, id: Id, jsonrpc: Option<Version>) -> Self {
		match result {
			Ok(result) => Output::Success(Success {
				id: id,
				jsonrpc: jsonrpc,
				result: result,
			}),
			Err(error) => Output::Failure(Failure {
				id: id,
				jsonrpc: jsonrpc,
				error: error,
			}),
		}
	}

	/// Creates new failure output indicating malformed request.
	pub fn invalid_request(id: Id, jsonrpc: Option<Version>) -> Self {
		Output::Failure(Failure {
			id: id,
			jsonrpc: jsonrpc,
			error: Error::new(ErrorCode::InvalidRequest),
		})
	}

	/// Get the jsonrpc protocol version.
	pub fn version(&self) -> Option<Version> {
		match *self {
			Output::Success(ref s) => s.jsonrpc,
			Output::Failure(ref f) => f.jsonrpc,
		}
	}

	/// Get the correlation id.
	pub fn id(&self) -> &Id {
		match *self {
			Output::Success(ref s) => &s.id,
			Output::Failure(ref f) => &f.id,
		}
	}
}

impl From<Output> for Result<Value, Error> {
	/// Convert into a result. Will be `Ok` if it is a `Success` and `Err` if `Failure`.
	fn from(output: Output) -> Result<Value, Error> {
		match output {
			Output::Success(s) => Ok(s.result),
			Output::Failure(f) => Err(f.error),
		}
	}
}

impl<'a> Deserialize<'a> for Output {
	fn deserialize<D>(deserializer: D) -> Result<Output, D::Error>
	where D: Deserializer<'a> {
		let v: Value = try!(Deserialize::deserialize(deserializer));
		from_value(v.clone()).map(Output::Failure)
			.or_else(|_| from_value(v).map(Output::Success))
			.map_err(|_| D::Error::custom("")) // types must match
	}
}

impl Serialize for Output {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where S: Serializer {
		match *self {
			Output::Success(ref s) => s.serialize(serializer),
			Output::Failure(ref f) => f.serialize(serializer)
		}
	}
}

/// Synchronous response
#[derive(Debug, PartialEq)]
pub enum Response {
	/// Single response
	Single(Output),
	/// Response to batch request (batch of responses)
	Batch(Vec<Output>)
}

impl<'a> Deserialize<'a> for Response {
	fn deserialize<D>(deserializer: D) -> Result<Response, D::Error>
	where D: Deserializer<'a> {
		let v: Value = try!(Deserialize::deserialize(deserializer));
		from_value(v.clone()).map(Response::Batch)
			.or_else(|_| from_value(v).map(Response::Single))
			.map_err(|_| D::Error::custom("")) // types must match
	}
}

impl Serialize for Response {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where S: Serializer {
		match *self {
			Response::Single(ref o) => o.serialize(serializer),
			Response::Batch(ref b) => b.serialize(serializer)
		}
	}
}

impl Response {
	/// Creates new `Response` with given error and `Version`
	pub fn from(error: Error, jsonrpc: Option<Version>) -> Self {
		Failure {
			id: Id::Null,
			jsonrpc: jsonrpc,
			error: error,
		}.into()
	}
}

impl From<Failure> for Response {
	fn from(failure: Failure) -> Self {
		Response::Single(Output::Failure(failure))
	}
}

impl From<Success> for Response {
	fn from(success: Success) -> Self {
		Response::Single(Output::Success(success))
	}
}

#[test]
fn success_output_serialize() {
	use serde_json;
	use serde_json::Value;

	let so = Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&so).unwrap();
	assert_eq!(serialized, r#"{"jsonrpc":"2.0","result":1,"id":1}"#);
}

#[test]
fn success_output_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dso = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;

	let deserialized: Output = serde_json::from_str(dso).unwrap();
	assert_eq!(deserialized, Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	}));
}

#[test]
fn failure_output_serialize() {
	use serde_json;

	let fo = Output::Failure(Failure {
		jsonrpc: Some(Version::V2),
		error: Error::parse_error(),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&fo).unwrap();
	assert_eq!(serialized, r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#);
}

#[test]
fn failure_output_serialize_jsonrpc_1() {
	use serde_json;

	let fo = Output::Failure(Failure {
		jsonrpc: None,
		error: Error::parse_error(),
		id: Id::Num(1)
	});

	let serialized = serde_json::to_string(&fo).unwrap();
	assert_eq!(serialized, r#"{"error":{"code":-32700,"message":"Parse error"},"id":1}"#);
}

#[test]
fn failure_output_deserialize() {
	use serde_json;

	let dfo = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#;

	let deserialized: Output = serde_json::from_str(dfo).unwrap();
	assert_eq!(deserialized, Output::Failure(Failure {
		jsonrpc: Some(Version::V2),
		error: Error::parse_error(),
		id: Id::Num(1)
	}));
}

#[test]
fn single_response_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dsr = r#"{"jsonrpc":"2.0","result":1,"id":1}"#;

	let deserialized: Response = serde_json::from_str(dsr).unwrap();
	assert_eq!(deserialized, Response::Single(Output::Success(Success {
		jsonrpc: Some(Version::V2),
		result: Value::from(1),
		id: Id::Num(1)
	})));
}

#[test]
fn batch_response_deserialize() {
	use serde_json;
	use serde_json::Value;

	let dbr = r#"[{"jsonrpc":"2.0","result":1,"id":1},{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}]"#;

	let deserialized: Response = serde_json::from_str(dbr).unwrap();
	assert_eq!(deserialized, Response::Batch(vec![
		Output::Success(Success {
			jsonrpc: Some(Version::V2),
			result: Value::from(1),
			id: Id::Num(1)
		}),
		Output::Failure(Failure {
			jsonrpc: Some(Version::V2),
			error: Error::parse_error(),
			id: Id::Num(1)
		})
	]));
}
<|endoftext|>


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

use support::{project, execs};
use hamcrest::assert_that;

fn setup() {}

test!(adding_and_removing_packages {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.1"
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("generate-lockfile"),
                execs().with_status(0));

    let lockfile = p.root().join("Cargo.lock");
    let toml = p.root().join("Cargo.toml");
    let mut lock1 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock1).unwrap();

    // add a dep
    File::create(&toml).unwrap().write_all(br#"
        [package]
        name = "foo"
        authors = []
        version = "0.0.1"

        [dependencies.bar]
        path = "bar"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock2 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock2).unwrap();
    assert!(lock1 != lock2);

    // change the dep
    File::create(&p.root().join("bar/Cargo.toml")).unwrap().write_all(br#"
        [package]
        name = "bar"
        authors = []
        version = "0.0.2"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock3 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock3).unwrap();
    assert!(lock1 != lock3);
    assert!(lock2 != lock3);

    // remove the dep
    File::create(&toml).unwrap().write_all(br#"
        [package]
        name = "foo"
        authors = []
        version = "0.0.1"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock4 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock4).unwrap();
    assert_eq!(lock1, lock4);
});

test!(preserve_metadata {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.1"
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("generate-lockfile"),
                execs().with_status(0));

    let metadata = r#"
[metadata]
bar = "baz"
foo = "bar"
"#;
    let lockfile = p.root().join("Cargo.lock");
    {
        let mut lock = String::new();
        File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
        let data = lock + metadata;
        File::create(&lockfile).unwrap().write_all(data.as_bytes()).unwrap();
    }

    // Build and make sure the metadata is still there
    assert_that(p.cargo("build"),
                execs().with_status(0));
    let mut lock = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
    assert!(lock.contains(metadata.trim()), "{}", lock);

    // Update and make sure the metadata is still there
    assert_that(p.cargo("update"),
                execs().with_status(0));
    let mut lock = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
    assert!(lock.contains(metadata.trim()), "{}", lock);
});
<commit_msg>Add a test for #2076, preservation of line endings style<commit_after>use std::fs::File;
use std::io::prelude::*;

use support::{project, execs};
use hamcrest::{assert_that, existing_file};

fn setup() {}

test!(adding_and_removing_packages {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.1"
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("generate-lockfile"),
                execs().with_status(0));

    let lockfile = p.root().join("Cargo.lock");
    let toml = p.root().join("Cargo.toml");
    let mut lock1 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock1).unwrap();

    // add a dep
    File::create(&toml).unwrap().write_all(br#"
        [package]
        name = "foo"
        authors = []
        version = "0.0.1"

        [dependencies.bar]
        path = "bar"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock2 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock2).unwrap();
    assert!(lock1 != lock2);

    // change the dep
    File::create(&p.root().join("bar/Cargo.toml")).unwrap().write_all(br#"
        [package]
        name = "bar"
        authors = []
        version = "0.0.2"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock3 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock3).unwrap();
    assert!(lock1 != lock3);
    assert!(lock2 != lock3);

    // remove the dep
    File::create(&toml).unwrap().write_all(br#"
        [package]
        name = "foo"
        authors = []
        version = "0.0.1"
    "#).unwrap();
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));
    let mut lock4 = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock4).unwrap();
    assert_eq!(lock1, lock4);
});

test!(preserve_metadata {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.1"
        "#)
        .file("bar/src/lib.rs", "");

    assert_that(p.cargo_process("generate-lockfile"),
                execs().with_status(0));

    let metadata = r#"
[metadata]
bar = "baz"
foo = "bar"
"#;
    let lockfile = p.root().join("Cargo.lock");
    {
        let mut lock = String::new();
        File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
        let data = lock + metadata;
        File::create(&lockfile).unwrap().write_all(data.as_bytes()).unwrap();
    }

    // Build and make sure the metadata is still there
    assert_that(p.cargo("build"),
                execs().with_status(0));
    let mut lock = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
    assert!(lock.contains(metadata.trim()), "{}", lock);

    // Update and make sure the metadata is still there
    assert_that(p.cargo("update"),
                execs().with_status(0));
    let mut lock = String::new();
    File::open(&lockfile).unwrap().read_to_string(&mut lock).unwrap();
    assert!(lock.contains(metadata.trim()), "{}", lock);
});

test!(preserve_line_endings_issue_2076 {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            authors = []
            version = "0.0.1"
        "#)
        .file("src/main.rs", "fn main() {}")
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            authors = []
            version = "0.0.1"
        "#)
        .file("bar/src/lib.rs", "");

    let lockfile = p.root().join("Cargo.lock");
    assert_that(p.cargo_process("generate-lockfile"),
                execs().with_status(0));
    assert_that(&lockfile,
                existing_file());
    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));

    let mut lock0 = String::new();
    {
        File::open(&lockfile).unwrap().read_to_string(&mut lock0).unwrap();
    }

    assert!(lock0.starts_with("[root]\n"));

    let lock1 = lock0.replace("\n", "\r\n");
    {
        File::create(&lockfile).unwrap().write_all(lock1.as_bytes()).unwrap();
    }

    assert_that(p.cargo("generate-lockfile"),
                execs().with_status(0));

    let mut lock2 = String::new();
    {
        File::open(&lockfile).unwrap().read_to_string(&mut lock2).unwrap();
    }

    assert!(lock2.starts_with("[root]\r\n"));
    assert_eq!(lock1, lock2);
});
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate pkg_config;

use bindgen::Builder;
use pkg_config::Config;
use std::env;
use std::path::PathBuf;

fn main() {
    let mut builder = Builder::default();

    let gdal = Config::new().probe("gdal").unwrap();
    for path in &gdal.include_paths {
        builder = builder.clang_arg("-I");
        builder = builder.clang_arg(path.to_str().unwrap());
    }

    let bindings = builder
        .header("wrapper.h")
        .prepend_enum_name(false)
        .constified_enum_module(".*")
        .ctypes_prefix("libc")
        .whitelist_function("CPL.*")
        .whitelist_function("GDAL.*")
        .whitelist_function("OGR.*")
        .whitelist_function("OSR.*")
        .whitelist_function("OCT.*")
        .whitelist_function("VSI.*")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Bring back the Windows linking code<commit_after>extern crate bindgen;
extern crate pkg_config;

use bindgen::Builder;
use pkg_config::Config;
use std::env;
use std::path::PathBuf;

fn main() {
    #[cfg(windows)]
    {
        use std::path::Path;

        // get the path to GDAL_HOME
        let home_path = env::var("GDAL_HOME").expect("Environment variable $GDAL_HOME not found!");

        // detect the path to gdal_i.lib (works for MSVC and GNU)
        let lib_suffix = "_i";
        let lib_search_path = Path::new(&home_path).join("lib");
        let lib_path = lib_search_path.join(&format!("{}{}.lib", lib_name, lib_suffix));

        if lib_search_path.exists() && lib_path.exists() {
            println!("cargo:rustc-link-search={}", lib_search_path.to_string_lossy());
            println!("cargo:rustc-link-lib={}={}", link_type, format!("{}{}",lib_name, lib_suffix));
        } else {
            #[cfg(target_env="msvc")]
            {
                panic!("windows-msvc requires gdal_i.lib to be found in $GDAL_HOME\\lib.");
            }

            #[cfg(target_env="gnu")]
            {
                // detect if a gdal{version}.dll is available
                let versions = [201, 200, 111, 110];
                let bin_path = Path::new(&home_path).join("bin");
                if let Some(version) = versions.iter().find(|v| bin_path.join(&format!("{}{}.dll", lib_name, v)).exists()){
                    println!("cargo:rustc-link-search={}", bin_path.to_string_lossy());
                    println!("cargo:rustc-link-lib={}={}", link_type, format!("{}{}",lib_name, version));
                }
                else {
                    panic!("windows-gnu requires either gdal_i.lib in $GDAL_HOME\\lib OR gdal{version}.dll in $GDAL_HOME\\bin.");
                }
            }
        }
    }

    let mut builder = Builder::default();

    if let Ok(gdal) = Config::new().probe("gdal") {
        for path in &gdal.include_paths {
            builder = builder.clang_arg("-I");
            builder = builder.clang_arg(path.to_str().unwrap());
        }
    }

    let bindings = builder
        .header("wrapper.h")
        .prepend_enum_name(false)
        .constified_enum_module(".*")
        .ctypes_prefix("libc")
        .whitelist_function("CPL.*")
        .whitelist_function("GDAL.*")
        .whitelist_function("OGR.*")
        .whitelist_function("OSR.*")
        .whitelist_function("OCT.*")
        .whitelist_function("VSI.*")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>//! Partitions a list of files into disjoint subsets.
//!
//! Files which do not belong to any explicitly configured `FileSet` belong to
//! the default `FileSet`.
use std::{fmt, iter};

use rustc_hash::FxHashMap;

use crate::{FileId, Vfs, VfsPath};

#[derive(Default, Clone, Eq, PartialEq)]
pub struct FileSet {
    files: FxHashMap<VfsPath, FileId>,
    paths: FxHashMap<FileId, VfsPath>,
}

impl FileSet {
    pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        let mut base = self.paths[&anchor].clone();
        base.pop();
        let path = base.join(path)?;
        let res = self.files.get(&path).copied();
        res
    }
    pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
        self.files.insert(path.clone(), file_id);
        self.paths.insert(file_id, path);
    }
    pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
        self.paths.keys().copied()
    }
}

impl fmt::Debug for FileSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
    }
}

#[derive(Debug)]
pub struct FileSetConfig {
    n_file_sets: usize,
    roots: Vec<(VfsPath, usize)>,
}

impl Default for FileSetConfig {
    fn default() -> Self {
        FileSetConfig::builder().build()
    }
}

impl FileSetConfig {
    pub fn builder() -> FileSetConfigBuilder {
        FileSetConfigBuilder::default()
    }
    pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
        let mut res = vec![FileSet::default(); self.len()];
        for (file_id, path) in vfs.iter() {
            let root = self.classify(&path);
            res[root].insert(file_id, path)
        }
        res
    }
    fn len(&self) -> usize {
        self.n_file_sets
    }
    fn classify(&self, path: &VfsPath) -> usize {
        let idx = match self.roots.binary_search_by(|(p, _)| p.cmp(path)) {
            Ok(it) => it,
            Err(it) => it.saturating_sub(1),
        };
        if !self.roots.is_empty() && path.starts_with(&self.roots[idx].0) {
            self.roots[idx].1
        } else {
            self.len() - 1
        }
    }
}

pub struct FileSetConfigBuilder {
    roots: Vec<Vec<VfsPath>>,
}

impl Default for FileSetConfigBuilder {
    fn default() -> Self {
        FileSetConfigBuilder { roots: Vec::new() }
    }
}

impl FileSetConfigBuilder {
    pub fn len(&self) -> usize {
        self.roots.len()
    }
    pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
        self.roots.push(roots)
    }
    pub fn build(self) -> FileSetConfig {
        let n_file_sets = self.roots.len() + 1;
        let mut roots: Vec<(VfsPath, usize)> = self
            .roots
            .into_iter()
            .enumerate()
            .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i)))
            .collect();
        roots.sort();
        FileSetConfig { n_file_sets, roots }
    }
}
<commit_msg>Fix symbol search in salsa<commit_after>//! Partitions a list of files into disjoint subsets.
//!
//! Files which do not belong to any explicitly configured `FileSet` belong to
//! the default `FileSet`.
use std::{fmt, mem};

use rustc_hash::FxHashMap;

use crate::{FileId, Vfs, VfsPath};

#[derive(Default, Clone, Eq, PartialEq)]
pub struct FileSet {
    files: FxHashMap<VfsPath, FileId>,
    paths: FxHashMap<FileId, VfsPath>,
}

impl FileSet {
    pub fn len(&self) -> usize {
        self.files.len()
    }
    pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        let mut base = self.paths[&anchor].clone();
        base.pop();
        let path = base.join(path)?;
        let res = self.files.get(&path).copied();
        res
    }
    pub fn insert(&mut self, file_id: FileId, path: VfsPath) {
        self.files.insert(path.clone(), file_id);
        self.paths.insert(file_id, path);
    }
    pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
        self.paths.keys().copied()
    }
}

impl fmt::Debug for FileSet {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FileSet").field("n_files", &self.files.len()).finish()
    }
}

// Invariant: if k1 is a prefix of k2, then they are in different buckets (k2
// is closer to 0th bucket).
// FIXME: replace with an actual trie some day.
type BadTrie<K, V> = Vec<Vec<(K, V)>>;

#[derive(Debug)]
pub struct FileSetConfig {
    n_file_sets: usize,
    trie: BadTrie<VfsPath, usize>,
}

impl Default for FileSetConfig {
    fn default() -> Self {
        FileSetConfig::builder().build()
    }
}

impl FileSetConfig {
    pub fn builder() -> FileSetConfigBuilder {
        FileSetConfigBuilder::default()
    }
    pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
        let mut res = vec![FileSet::default(); self.len()];
        for (file_id, path) in vfs.iter() {
            let root = self.classify(&path);
            res[root].insert(file_id, path)
        }
        res
    }
    fn len(&self) -> usize {
        self.n_file_sets
    }
    fn classify(&self, path: &VfsPath) -> usize {
        find_ancestor(&self.trie, path, is_prefix).copied().unwrap_or(self.len() - 1)
    }
}

pub struct FileSetConfigBuilder {
    roots: Vec<Vec<VfsPath>>,
}

impl Default for FileSetConfigBuilder {
    fn default() -> Self {
        FileSetConfigBuilder { roots: Vec::new() }
    }
}

impl FileSetConfigBuilder {
    pub fn len(&self) -> usize {
        self.roots.len()
    }
    pub fn add_file_set(&mut self, roots: Vec<VfsPath>) {
        self.roots.push(roots)
    }
    pub fn build(self) -> FileSetConfig {
        let n_file_sets = self.roots.len() + 1;

        let mut trie = BadTrie::new();

        for (i, paths) in self.roots.into_iter().enumerate() {
            for p in paths {
                insert(&mut trie, p, i, is_prefix);
            }
        }
        trie.iter_mut().for_each(|it| it.sort());
        FileSetConfig { n_file_sets, trie }
    }
}

fn is_prefix(short: &VfsPath, long: &VfsPath) -> bool {
    long.starts_with(short)
}

fn insert<K: Ord, V, P: Fn(&K, &K) -> bool>(
    trie: &mut BadTrie<K, V>,
    mut key: K,
    mut value: V,
    is_prefix: P,
) {
    'outer: for level in 0.. {
        if trie.len() == level {
            trie.push(Vec::new())
        }
        for (k, v) in trie[level].iter_mut() {
            if is_prefix(&key, k) {
                continue 'outer;
            }
            if is_prefix(k, &key) {
                mem::swap(k, &mut key);
                mem::swap(v, &mut value);
                continue 'outer;
            }
        }
        trie[level].push((key, value));
        return;
    }
}

fn find_ancestor<'t, K: Ord, V, P: Fn(&K, &K) -> bool>(
    trie: &'t BadTrie<K, V>,
    key: &K,
    is_prefix: P,
) -> Option<&'t V> {
    for bucket in trie {
        let idx = match bucket.binary_search_by(|(k, _)| k.cmp(key)) {
            Ok(it) => it,
            Err(it) => it.saturating_sub(1),
        };
        if !bucket.is_empty() && is_prefix(&bucket[idx].0, key) {
            return Some(&bucket[idx].1);
        }
    }
    None
}

#[test]
fn test_partitioning() {
    let mut file_set = FileSetConfig::builder();
    file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
    file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]);
    let file_set = file_set.build();

    let mut vfs = Vfs::default();
    vfs.set_file_contents(VfsPath::new_virtual_path("/foo/src/lib.rs".into()), Some(Vec::new()));
    vfs.set_file_contents(
        VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()),
        Some(Vec::new()),
    );
    vfs.set_file_contents(
        VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()),
        Some(Vec::new()),
    );
    vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new()));

    let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
    assert_eq!(partition, vec![2, 1, 1]);
}
<|endoftext|>


<commit_before>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
#[macro_use] extern crate libimagerror;

use std::result::Result as RResult;
use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::store::FileLockEntry;
use libimagerror::trace::trace_error;

mod error;
mod ui;
mod viewer;

use error::{ViewError, ViewErrorKind};
use ui::build_ui;
use viewer::Viewer;
use viewer::ViewInformation;
use viewer::stdout::StdoutViewer;

type Result<T> = RResult<T, ViewError>;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id = rt.cli().value_of("id").unwrap(); // enforced by clap

    if rt.cli().is_present("versions") {
        if let Err(e) = view_versions_of(entry_id, &rt) {
            trace_error(&e);
            exit(1); // we can afford not-executing destructors here
        }
    } else {
        let entry_version   = rt.cli().value_of("version");
        let view_header     = rt.cli().is_present("view-header");
        let view_content    = rt.cli().is_present("view-content");
        let view_copy       = rt.cli().is_present("view-copy");
        let keep_copy       = rt.cli().is_present("keep-copy");

        let scmd = rt.cli().subcommand_matches("view-in");
        if scmd.is_none() {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        let scmd = scmd.unwrap();

        let viewer = {
            if scmd.is_present("view-in-stdout") {
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-ui") {
                warn!("Viewing in UI is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-browser") {
                warn!("Viewing in browser is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-texteditor") {
                warn!("Viewing in texteditor is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-custom") {
                warn!("Viewing in custom is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else {
                Box::new(StdoutViewer::new())
            }
        };

        let entry = load_entry(entry_id, entry_version, &rt);
        if entry.is_err() {
            trace_error(&entry.unwrap_err());
            exit(1); // we can afford not-executing destructors here
        }
        let entry = entry.unwrap();

        let view_info = ViewInformation {
            entry:          entry,
            view_header:    view_header,
            view_content:   view_content,
            view_copy:      view_copy,
            keep_copy:      keep_copy,
        };

        viewer.view(view_info);
    }
}

// TODO: This is a shameless adaption of imag-store/src/util.rs
fn load_entry<'a>(id: &str,
                  version: Option<&str>,
                  rt: &'a Runtime)
    -> Result<FileLockEntry<'a>>
{
    debug!("Checking path element for version");

    let version = {
        if version.is_none() {
            let r = id.split('~').last();
            if r.is_none() {
                warn!("No version");
                return Err(ViewError::new(ViewErrorKind::NoVersion, None));
            } else {
                r.unwrap()
            }
        } else {
            version.unwrap()
        }
    };

    debug!("Building path from {:?} and {:?}", id, version);
    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~{}", &id[1..id.len()], version));
    } else {
        path.push(format!("{}~{}", id, version));
    }

    // the above is the adaption...

    rt.store().retrieve(path)
        .map_err(|e| ViewError::new(ViewErrorKind::StoreError, Some(Box::new(e))))
}

fn view_versions_of(id: &str, rt: &Runtime) -> Result<()> {
    use glob::glob;

    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~*", &id[1..id.len()]));
    } else {
        path.push(format!("{}~*", id));
    }

    if let Some(path) = path.to_str() {
        match glob(path) {
            Ok(paths) => {
                for entry in paths {
                    match entry {
                        Ok(path) => println!("{}", path.file_name().and_then(|s| s.to_str()).unwrap()),
                        Err(e)   => trace_error(e.error()),
                    }
                }
                Ok(())
            },
            Err(e) => {
                debug!("Error in pattern");
                Err(ViewError::new(ViewErrorKind::PatternError, Some(Box::new(e))))
            },
        }
    } else {
        warn!("Could not build glob() argument!");
        Err(ViewError::new(ViewErrorKind::GlobBuildError, None))
    }
}

<commit_msg>Abort if the passed id contains a version part<commit_after>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
#[macro_use] extern crate libimagerror;

use std::result::Result as RResult;
use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::store::FileLockEntry;
use libimagerror::trace::trace_error;

mod error;
mod ui;
mod viewer;

use error::{ViewError, ViewErrorKind};
use ui::build_ui;
use viewer::Viewer;
use viewer::ViewInformation;
use viewer::stdout::StdoutViewer;

type Result<T> = RResult<T, ViewError>;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id = rt.cli().value_of("id").unwrap(); // enforced by clap

    if entry_id.contains("~") {
        error!("The --id argument does not need the version part");
        exit(1);
    }

    if rt.cli().is_present("versions") {
        if let Err(e) = view_versions_of(entry_id, &rt) {
            trace_error(&e);
            exit(1); // we can afford not-executing destructors here
        }
    } else {
        let entry_version   = rt.cli().value_of("version");
        let view_header     = rt.cli().is_present("view-header");
        let view_content    = rt.cli().is_present("view-content");
        let view_copy       = rt.cli().is_present("view-copy");
        let keep_copy       = rt.cli().is_present("keep-copy");

        let scmd = rt.cli().subcommand_matches("view-in");
        if scmd.is_none() {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        let scmd = scmd.unwrap();

        let viewer = {
            if scmd.is_present("view-in-stdout") {
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-ui") {
                warn!("Viewing in UI is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-browser") {
                warn!("Viewing in browser is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-texteditor") {
                warn!("Viewing in texteditor is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else if scmd.is_present("view-in-custom") {
                warn!("Viewing in custom is currently not supported, switch to stdout");
                Box::new(StdoutViewer::new())
            } else {
                Box::new(StdoutViewer::new())
            }
        };

        let entry = load_entry(entry_id, entry_version, &rt);
        if entry.is_err() {
            trace_error(&entry.unwrap_err());
            exit(1); // we can afford not-executing destructors here
        }
        let entry = entry.unwrap();

        let view_info = ViewInformation {
            entry:          entry,
            view_header:    view_header,
            view_content:   view_content,
            view_copy:      view_copy,
            keep_copy:      keep_copy,
        };

        viewer.view(view_info);
    }
}

// TODO: This is a shameless adaption of imag-store/src/util.rs
fn load_entry<'a>(id: &str,
                  version: Option<&str>,
                  rt: &'a Runtime)
    -> Result<FileLockEntry<'a>>
{
    debug!("Checking path element for version");

    let version = {
        if version.is_none() {
            let r = id.split('~').last();
            if r.is_none() {
                warn!("No version");
                return Err(ViewError::new(ViewErrorKind::NoVersion, None));
            } else {
                r.unwrap()
            }
        } else {
            version.unwrap()
        }
    };

    debug!("Building path from {:?} and {:?}", id, version);
    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~{}", &id[1..id.len()], version));
    } else {
        path.push(format!("{}~{}", id, version));
    }

    // the above is the adaption...

    rt.store().retrieve(path)
        .map_err(|e| ViewError::new(ViewErrorKind::StoreError, Some(Box::new(e))))
}

fn view_versions_of(id: &str, rt: &Runtime) -> Result<()> {
    use glob::glob;

    let mut path = rt.store().path().clone();

    if id.starts_with('/') {
        path.push(format!("{}~*", &id[1..id.len()]));
    } else {
        path.push(format!("{}~*", id));
    }

    if let Some(path) = path.to_str() {
        match glob(path) {
            Ok(paths) => {
                for entry in paths {
                    match entry {
                        Ok(path) => println!("{}", path.file_name().and_then(|s| s.to_str()).unwrap()),
                        Err(e)   => trace_error(e.error()),
                    }
                }
                Ok(())
            },
            Err(e) => {
                debug!("Error in pattern");
                Err(ViewError::new(ViewErrorKind::PatternError, Some(Box::new(e))))
            },
        }
    } else {
        warn!("Could not build glob() argument!");
        Err(ViewError::new(ViewErrorKind::GlobBuildError, None))
    }
}

<|endoftext|>