<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .with_depth_buffer(24)
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let (w, h) = display.get_framebuffer_dimensions();
        let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = cgmath::Vector3::new(0.0, 0.0, 0.0);
        let eye = at - dir.mul_s(250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&eye),
                                            &cgmath::Point3::from_vec(&at),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let pos = cgmath::Matrix4::from_translation(&eye.mul_s(-1.0));
        let matrix = persp * view * pos;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.01, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Fix backface culling for other example too<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .with_depth_buffer(24)
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let (w, h) = display.get_framebuffer_dimensions();
        let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = cgmath::Vector3::new(0.0, 0.0, 0.0);
        let eye = at - dir.mul_s(250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&eye),
                                            &cgmath::Point3::from_vec(&at),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let pos = cgmath::Matrix4::from_translation(&eye.mul_s(-1.0));
        let matrix = persp * view * pos;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.01, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Enable merges!<commit_after><|endoftext|>


<commit_before>use std::vec::IntoIter;

use clap::ArgMatches;
use regex::Regex;

use module::{CommandEnv, CommandResult, Module, ModuleError};
use module::bm::header::{build_header, get_tags_from_header};
use runtime::Runtime;
use storage::backend::StorageBackendError;
use storage::file::File;
use storage::json::parser::JsonHeaderParser;
use storage::parser::Parser;
use ui::file::{FilePrinter, TablePrinter};

pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult {
    use url::Url;

    let url = env.matches.value_of("url").unwrap();

    if let Err(e) = Url::parse(url) {
        info!("Not an URL: '{}'", url);
        info!("  this will turn into an hard error before 0.1.0");
        debug!("URL parsing error: {:?}", e);
    }

    let tags = get_tags(env.rt, env.matches);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    let header  = build_header(&String::from(url), &tags);
    let file    = File::new_with_header(module, header);
    let parser  = Parser::new(JsonHeaderParser::new(None));
    let putres  = env.bk.put_file(file, &parser);

    putres.map_err(|sberr| {
        let mut err = ModuleError::new("Storage Backend Error");
        err.caused_by = Some(Box::new(sberr));
        err
    })
}

pub fn list_command(module: &Module, env: CommandEnv) -> CommandResult {
    let printer = TablePrinter::new(env.rt.is_verbose(), env.rt.is_debugging());
    let files   = get_filtered_files_from_backend(module, &env);

    debug!("Printing files now");
    files.map(|f| printer.print_files(f));

    Ok(())
}

pub fn remove_command(module: &Module, env: CommandEnv) -> CommandResult {
    fn remove_by_id(module: &Module, env: CommandEnv, id: String, checked: bool) -> CommandResult {
        let parser = Parser::new(JsonHeaderParser::new(None));
        let file = env.bk
            .get_file_by_id(module, &id.into(), &parser)
            .unwrap_or({
                info!("No files found");
                return Ok(())
            });

        debug!("Remove file: {:?}", file);

        if let Err(e) = env.bk.remove_file(module, file, checked) {
            debug!("Remove failed");
            let mut err = ModuleError::new("Removing file failed");
            err.caused_by = Some(Box::new(e));
            Err(err)
        } else {
            info!("Remove worked");
            Ok(())
        }
    }

    fn remove_by_filtering(module: &Module, env: CommandEnv, checked: bool) -> CommandResult {
        get_filtered_files_from_backend(module, &env).and_then(|files| {
            let nfiles = files.len();
            info!("Removing {} Files", nfiles);

            let errs = files.map(|file| {
                    debug!("Remove file: {:?}", file);
                    env.bk.remove_file(module, file, checked)
                })
                .filter(|e| e.is_err())
                .map(|e| {
                    let err = e.err().unwrap();
                    warn!("Error occured in Filesystem operation: {}", err);
                    err
                })
                .collect::<Vec<StorageBackendError>>();

            let nerrs = errs.len();

            if nerrs != 0 {
                warn!("{} Errors occured while removing {} files", nerrs, nfiles);
                let moderr = ModuleError::new("File removal failed");

                // TODO : Collect StorageBackendErrors

                Err(moderr)
            } else {
                Ok(())
            }
        })
    }

    let checked : bool = run_removal_checking(&env);
    debug!("Checked mode: {}", checked);

    if let Some(id) = get_id(env.rt, env.matches) {
        debug!("Remove by id: {}", id);
        remove_by_id(module, env, id, checked)
    } else {
        debug!("Remove more than one file");
        remove_by_filtering(module, env, checked)
    }
}

/*
 *
 * Private helpers
 *
 */

fn get_filtered_files_from_backend<'a>(module: &'a Module,
                                       env: &CommandEnv)
    -> Result<IntoIter<File<'a>>, ModuleError>
{
    let parser = Parser::new(JsonHeaderParser::new(None));
    let tags = get_tags(env.rt, env.matches);
    debug!("Tags: {:?}", tags);
    env.bk.iter_files(module, &parser)
        .map(|files| {
            let f = files.filter(|file| {
                debug!("Backend returns file: {:?}", file);
                if tags.len() != 0 {
                    debug!("Checking tags of: {:?}", file.id());
                    get_tags_from_header(&file.header()).iter()
                        .any(|t| tags.contains(t))
                } else {
                    true
                }
            }).filter(|file| {
                debug!("Checking matches of: {:?}", file.id());
                get_matcher(env.rt, env.matches)
                    .and_then(|r| Some(file.matches_with(&r)))
                    .unwrap_or(true)
            }).collect::<Vec<File>>();
            f.into_iter()
        }).map_err(|e| {
            debug!("Error from Backend: {:?}", e);
            let mut merr = ModuleError::new("Could not filter files");
            merr.caused_by = Some(Box::new(e));
            merr
        })
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

    fn reject_if_with_spaces(e: &String) -> bool {
        if e.contains(" ") {
            warn!("Tag contains spaces: '{}'", e);
            false
        } else {
            true
        }
    }

    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags| {
        Some(tags.split(",")
                 .into_iter()
                 .map(|s| s.to_string())
                 .filter(|e| reject_if_with_spaces(e))
                 .collect()
          )
    }).or(Some(vec![])).unwrap()
}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

/*
 * Checks whether the commandline call was set to run the removal "checked",
 * so if another entry from the store refers to this ID, do not remove the file.
 */
fn run_removal_checking(env: &CommandEnv) -> bool {
    env.matches.is_present("check")
}
<commit_msg>Remove variable, use expression directly<commit_after>use std::vec::IntoIter;

use clap::ArgMatches;
use regex::Regex;

use module::{CommandEnv, CommandResult, Module, ModuleError};
use module::bm::header::{build_header, get_tags_from_header};
use runtime::Runtime;
use storage::backend::StorageBackendError;
use storage::file::File;
use storage::json::parser::JsonHeaderParser;
use storage::parser::Parser;
use ui::file::{FilePrinter, TablePrinter};

pub fn add_command(module: &Module, env: CommandEnv) -> CommandResult {
    use url::Url;

    let url = env.matches.value_of("url").unwrap();

    if let Err(e) = Url::parse(url) {
        info!("Not an URL: '{}'", url);
        info!("  this will turn into an hard error before 0.1.0");
        debug!("URL parsing error: {:?}", e);
    }

    let tags = get_tags(env.rt, env.matches);
    info!("Adding url '{}' with tags '{:?}'", url, tags);

    let header  = build_header(&String::from(url), &tags);
    let file    = File::new_with_header(module, header);
    let parser  = Parser::new(JsonHeaderParser::new(None));
    let putres  = env.bk.put_file(file, &parser);

    putres.map_err(|sberr| {
        let mut err = ModuleError::new("Storage Backend Error");
        err.caused_by = Some(Box::new(sberr));
        err
    })
}

pub fn list_command(module: &Module, env: CommandEnv) -> CommandResult {
    let printer = TablePrinter::new(env.rt.is_verbose(), env.rt.is_debugging());
    let files   = get_filtered_files_from_backend(module, &env);

    debug!("Printing files now");
    files.map(|f| printer.print_files(f));

    Ok(())
}

pub fn remove_command(module: &Module, env: CommandEnv) -> CommandResult {
    fn remove_by_id(module: &Module, env: CommandEnv, id: String, checked: bool) -> CommandResult {
        let parser = Parser::new(JsonHeaderParser::new(None));
        let file = env.bk
            .get_file_by_id(module, &id.into(), &parser)
            .unwrap_or({
                info!("No files found");
                return Ok(())
            });

        debug!("Remove file: {:?}", file);

        if let Err(e) = env.bk.remove_file(module, file, checked) {
            debug!("Remove failed");
            let mut err = ModuleError::new("Removing file failed");
            err.caused_by = Some(Box::new(e));
            Err(err)
        } else {
            info!("Remove worked");
            Ok(())
        }
    }

    fn remove_by_filtering(module: &Module, env: CommandEnv, checked: bool) -> CommandResult {
        get_filtered_files_from_backend(module, &env).and_then(|files| {
            let nfiles = files.len();
            info!("Removing {} Files", nfiles);

            let errs = files.map(|file| {
                    debug!("Remove file: {:?}", file);
                    env.bk.remove_file(module, file, checked)
                })
                .filter(|e| e.is_err())
                .map(|e| {
                    let err = e.err().unwrap();
                    warn!("Error occured in Filesystem operation: {}", err);
                    err
                })
                .collect::<Vec<StorageBackendError>>();

            if errs.len() != 0 {
                warn!("{} Errors occured while removing {} files", errs.len(), nfiles);
                let moderr = ModuleError::new("File removal failed");

                // TODO : Collect StorageBackendErrors

                Err(moderr)
            } else {
                Ok(())
            }
        })
    }

    let checked : bool = run_removal_checking(&env);
    debug!("Checked mode: {}", checked);

    if let Some(id) = get_id(env.rt, env.matches) {
        debug!("Remove by id: {}", id);
        remove_by_id(module, env, id, checked)
    } else {
        debug!("Remove more than one file");
        remove_by_filtering(module, env, checked)
    }
}

/*
 *
 * Private helpers
 *
 */

fn get_filtered_files_from_backend<'a>(module: &'a Module,
                                       env: &CommandEnv)
    -> Result<IntoIter<File<'a>>, ModuleError>
{
    let parser = Parser::new(JsonHeaderParser::new(None));
    let tags = get_tags(env.rt, env.matches);
    debug!("Tags: {:?}", tags);
    env.bk.iter_files(module, &parser)
        .map(|files| {
            let f = files.filter(|file| {
                debug!("Backend returns file: {:?}", file);
                if tags.len() != 0 {
                    debug!("Checking tags of: {:?}", file.id());
                    get_tags_from_header(&file.header()).iter()
                        .any(|t| tags.contains(t))
                } else {
                    true
                }
            }).filter(|file| {
                debug!("Checking matches of: {:?}", file.id());
                get_matcher(env.rt, env.matches)
                    .and_then(|r| Some(file.matches_with(&r)))
                    .unwrap_or(true)
            }).collect::<Vec<File>>();
            f.into_iter()
        }).map_err(|e| {
            debug!("Error from Backend: {:?}", e);
            let mut merr = ModuleError::new("Could not filter files");
            merr.caused_by = Some(Box::new(e));
            merr
        })
}

fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

    fn reject_if_with_spaces(e: &String) -> bool {
        if e.contains(" ") {
            warn!("Tag contains spaces: '{}'", e);
            false
        } else {
            true
        }
    }

    debug!("Fetching tags from commandline");
    sub.value_of("tags").and_then(|tags| {
        Some(tags.split(",")
                 .into_iter()
                 .map(|s| s.to_string())
                 .filter(|e| reject_if_with_spaces(e))
                 .collect()
          )
    }).or(Some(vec![])).unwrap()
}

fn get_matcher<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<Regex> {
    debug!("Fetching matcher from commandline");
    if let Some(s) = sub.value_of("match") {
        if let Ok(r) = Regex::new(s) {
            return Some(r)
        } else {
            error!("Regex error, continuing without regex");
        }
    }
    None

}

fn get_id<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Option<String> {
    debug!("Fetching id from commandline");
    sub.value_of("id").and_then(|s| Some(String::from(s)))
}

/*
 * Checks whether the commandline call was set to run the removal "checked",
 * so if another entry from the store refers to this ID, do not remove the file.
 */
fn run_removal_checking(env: &CommandEnv) -> bool {
    env.matches.is_present("check")
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));

            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        }
    }
}
<commit_msg>zhttpto using rust 0.12<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.12
//
// Note that this code has serious security risks! You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#![feature(globs)]

use std::io::*;
use std::str;

fn main() {

    let ip_addres = "127.0.0.1";
    let port = 4414;
    let mut acceptor = net::tcp::TcpListener::bind(ip_addres, port).listen().unwrap();

    println!("Listening on [{}] ...", ip_addres);

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        spawn(proc() {

            let mut stream = stream;

            match stream {
                Ok(ref mut s) => {
                    match s.peer_name() {
                        Ok(pn) => println!("Received connection from: [{}]", pn),
                        Err(_) => ()
                    }
                },
                Err(_) => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println!("Received request :\n{}", request_str);

            let response: Box<&str> =
                box "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        });
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>,
            results_done: ::capability::Promise<Box<ResultsDoneHook>, ::Error>)
            -> (::capability::Promise<(), ::Error>, Box<PipelineHook>);

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    fn write_target(&self, target: any_pointer::Builder) -> Option<Box<ClientHook>>;

    fn write_descriptor(&self, descriptor: any_pointer::Builder) -> Option<u32>;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    fn when_resolved(&self) -> ::capability::Promise<(), ::Error> {
        match self.when_more_resolved() {
            Some(promise) => {
                promise.then(|resolution|{
                    resolution.when_resolved()
                })
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ResultsDoneHook {
    fn add_ref(&self) -> Box<ResultsDoneHook>;
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

impl Clone for Box<ResultsDoneHook> {
    fn clone(&self) -> Box<ResultsDoneHook> {
        self.add_ref()
    }
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

#[derive(Clone, Copy)]
pub enum PipelineOp {
    Noop,
    GetPointerField(u16),
}

<commit_msg>ClientHook::get_innermost_client()<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use any_pointer;
use MessageSize;
use capability::{Params, Promise, Request, RemotePromise, Results};

pub trait ResponseHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

pub trait RequestHook {
    fn get<'a>(&'a mut self) -> any_pointer::Builder<'a>;
    fn get_brand(&self) -> usize;
    fn send<'a>(self: Box<Self>) -> RemotePromise<any_pointer::Owned>;
    fn tail_send(self: Box<Self>)
                 -> Option<(u32, ::capability::Promise<(), ::Error>, Box<PipelineHook>)>;
}

pub trait ClientHook {
    fn add_ref(&self) -> Box<ClientHook>;
    fn new_call(&self,
                interface_id: u64,
                method_id: u16,
                size_hint: Option<MessageSize>)
                -> Request<any_pointer::Owned, any_pointer::Owned>;

    fn call(&self, interface_id: u64, method_id: u16,
            params: Box<ParamsHook>, results: Box<ResultsHook>,
            results_done: ::capability::Promise<Box<ResultsDoneHook>, ::Error>)
            -> (::capability::Promise<(), ::Error>, Box<PipelineHook>);

    fn get_brand(&self) -> usize;
    fn get_ptr(&self) -> usize;

    fn write_target(&self, target: any_pointer::Builder) -> Option<Box<ClientHook>>;
    fn write_descriptor(&self, descriptor: any_pointer::Builder) -> Option<u32>;
    fn get_innermost_client(&self) -> Box<ClientHook>;

    /// If this ClientHook is a promise that has already resolved, returns the inner, resolved version
    /// of the capability.  The caller may permanently replace this client with the resolved one if
    /// desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
    /// `whenMoreResolved()` to distinguish between them.
    fn get_resolved(&self) -> Option<Box<ClientHook>>;

    /// If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
    /// promise that eventually resolves to a new client that is closer to being the final, settled
    /// client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
    /// should eventually produce a settled client.
    fn when_more_resolved(&self) -> Option<::capability::Promise<Box<ClientHook>, ::Error>>;

    /// Repeatedly calls whenMoreResolved() until it returns nullptr.
    fn when_resolved(&self) -> ::capability::Promise<(), ::Error> {
        match self.when_more_resolved() {
            Some(promise) => {
                promise.then(|resolution|{
                    resolution.when_resolved()
                })
            }
            None => {
                Promise::ok(())
            }
        }
    }
}

impl Clone for Box<ClientHook> {
    fn clone(&self) -> Box<ClientHook> {
        self.add_ref()
    }
}

pub trait ServerHook: 'static {
    fn new_client(server: Box<::capability::Server>) -> ::capability::Client;
}

pub trait ResultsHook {
    fn get<'a>(&'a mut self) -> ::Result<any_pointer::Builder<'a>>;
    fn allow_cancellation(&self);
    fn tail_call(self: Box<Self>, request: Box<RequestHook>) -> Promise<(), ::Error>;
    fn direct_tail_call(self: Box<Self>, request: Box<RequestHook>) ->
        (::capability::Promise<(), ::Error>, Box<PipelineHook>);
}

pub trait ResultsDoneHook {
    fn add_ref(&self) -> Box<ResultsDoneHook>;
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

impl Clone for Box<ResultsDoneHook> {
    fn clone(&self) -> Box<ResultsDoneHook> {
        self.add_ref()
    }
}

pub trait ParamsHook {
    fn get<'a>(&'a self) -> ::Result<any_pointer::Reader<'a>>;
}

// Where should this live?
pub fn internal_get_typed_params<T>(typeless: Params<any_pointer::Owned>) -> Params<T> {
    Params { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_typed_results<T>(typeless: Results<any_pointer::Owned>) -> Results<T> {
    Results { hook: typeless.hook, marker: ::std::marker::PhantomData }
}

pub fn internal_get_untyped_results<T>(typeful: Results<T>) -> Results<any_pointer::Owned> {
    Results { hook: typeful.hook, marker: ::std::marker::PhantomData }
}

pub trait PipelineHook {
    fn add_ref(&self) -> Box<PipelineHook>;
    fn get_pipelined_cap(&self, ops: &[PipelineOp]) -> Box<ClientHook>;

    /// Version of get_pipelined_cap() passing the array by move. May avoid a copy in some cases.
    /// Default implementation just calls the other version.
    fn get_pipelined_cap_move(&self, ops: Vec<PipelineOp>) -> Box<ClientHook> {
        self.get_pipelined_cap(&ops)
    }
}

impl Clone for Box<PipelineHook> {
    fn clone(&self) -> Box<PipelineHook> {
        self.add_ref()
    }
}

#[derive(Clone, Copy)]
pub enum PipelineOp {
    Noop,
    GetPointerField(u16),
}

<|endoftext|>


<commit_before>use std::io::{self, Read};

use rand::{Rng, RngCore};
use std::{cmp, iter};

use super::decoder::{DecoderReader, BUF_SIZE};
use crate::encode::encode_engine_string;
use crate::engine::fast_portable::FastPortable;
use crate::engine::DEFAULT_ENGINE;
use crate::tests::{random_alphabet, random_config, random_engine};
use crate::{decode_engine_vec, DecodeError};

#[test]
fn simple() {
    let tests: &[(&[u8], &[u8])] = &[
        (&b"0"[..], &b"MA=="[..]),
        (b"01", b"MDE="),
        (b"012", b"MDEy"),
        (b"0123", b"MDEyMw=="),
        (b"01234", b"MDEyMzQ="),
        (b"012345", b"MDEyMzQ1"),
        (b"0123456", b"MDEyMzQ1Ng=="),
        (b"01234567", b"MDEyMzQ1Njc="),
        (b"012345678", b"MDEyMzQ1Njc4"),
        (b"0123456789", b"MDEyMzQ1Njc4OQ=="),
    ][..];

    for (text_expected, base64data) in tests.iter() {
        // Read n bytes at a time.
        for n in 1..base64data.len() + 1 {
            let mut wrapped_reader = io::Cursor::new(base64data);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &DEFAULT_ENGINE);

            // handle errors as you normally would
            let mut text_got = Vec::new();
            let mut buffer = vec![0u8; n];
            while let Ok(read) = decoder.read(&mut buffer[..]) {
                if read == 0 {
                    break;
                }
                text_got.extend_from_slice(&buffer[..read]);
            }

            assert_eq!(
                text_got,
                *text_expected,
                "\nGot: {}\nExpected: {}",
                String::from_utf8_lossy(&text_got[..]),
                String::from_utf8_lossy(text_expected)
            );
        }
    }
}

// Make sure we error out on trailing junk.
#[test]
fn trailing_junk() {
    let tests: &[&[u8]] = &[&b"MDEyMzQ1Njc4*!@#$%^&"[..], b"MDEyMzQ1Njc4OQ== "][..];

    for base64data in tests.iter() {
        // Read n bytes at a time.
        for n in 1..base64data.len() + 1 {
            let mut wrapped_reader = io::Cursor::new(base64data);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &DEFAULT_ENGINE);

            // handle errors as you normally would
            let mut buffer = vec![0u8; n];
            let mut saw_error = false;
            loop {
                match decoder.read(&mut buffer[..]) {
                    Err(_) => {
                        saw_error = true;
                        break;
                    }
                    Ok(read) if read == 0 => break,
                    Ok(_) => (),
                }
            }

            assert!(saw_error);
        }
    }
}

#[test]
fn handles_short_read_from_delegate() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        bytes.truncate(size);
        rng.fill_bytes(&mut bytes[..size]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);
        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut wrapped_reader = io::Cursor::new(b64.as_bytes());
        let mut short_reader = RandomShortRead {
            delegate: &mut wrapped_reader,
            rng: &mut rng,
        };

        let mut decoder = DecoderReader::from(&mut short_reader, &engine);

        let decoded_len = decoder.read_to_end(&mut decoded).unwrap();
        assert_eq!(size, decoded_len);
        assert_eq!(&bytes[..], &decoded[..]);
    }
}

#[test]
fn read_in_short_increments() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        // leave room to play around with larger buffers
        decoded.extend(iter::repeat(0).take(size * 3));

        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut wrapped_reader = io::Cursor::new(&b64[..]);
        let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

        consume_with_short_reads_and_validate(&mut rng, &bytes[..], &mut decoded, &mut decoder);
    }
}

#[test]
fn read_in_short_increments_with_short_delegate_reads() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        // leave room to play around with larger buffers
        decoded.extend(iter::repeat(0).take(size * 3));

        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut base_reader = io::Cursor::new(&b64[..]);
        let mut decoder = DecoderReader::from(&mut base_reader, &engine);
        let mut short_reader = RandomShortRead {
            delegate: &mut decoder,
            rng: &mut rand::thread_rng(),
        };

        consume_with_short_reads_and_validate(&mut rng, &bytes[..], &mut decoded, &mut short_reader)
    }
}

#[test]
fn reports_invalid_last_symbol_correctly() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut b64_bytes = Vec::new();
    let mut decoded = Vec::new();
    let mut bulk_decoded = Vec::new();

    for _ in 0..1_000 {
        bytes.clear();
        b64.clear();
        b64_bytes.clear();

        let size = rng.gen_range(1, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        decoded.extend(iter::repeat(0).take(size));
        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let config = random_config(&mut rng);
        let alphabet = random_alphabet(&mut rng);
        // changing padding will cause invalid padding errors when we twiddle the last byte
        let engine = FastPortable::from(alphabet, config.with_encode_padding(false));
        encode_engine_string(&bytes[..], &mut b64, &engine);
        b64_bytes.extend(b64.bytes());
        assert_eq!(b64_bytes.len(), b64.len());

        // change the last character to every possible symbol. Should behave the same as bulk
        // decoding whether invalid or valid.
        for &s1 in alphabet.symbols.iter() {
            decoded.clear();
            bulk_decoded.clear();

            // replace the last
            *b64_bytes.last_mut().unwrap() = s1;
            let bulk_res = decode_engine_vec(&b64_bytes[..], &mut bulk_decoded, &engine);

            let mut wrapped_reader = io::Cursor::new(&b64_bytes[..]);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

            let stream_res = decoder.read_to_end(&mut decoded).map(|_| ()).map_err(|e| {
                e.into_inner()
                    .and_then(|e| e.downcast::<DecodeError>().ok())
            });

            assert_eq!(bulk_res.map_err(|e| Some(Box::new(e))), stream_res);
        }
    }
}

#[test]
fn reports_invalid_byte_correctly() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(1, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        rng.fill_bytes(&mut bytes[..size]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);
        // replace one byte, somewhere, with '*', which is invalid
        let bad_byte_pos = rng.gen_range(0, &b64.len());
        let mut b64_bytes = b64.bytes().collect::<Vec<u8>>();
        b64_bytes[bad_byte_pos] = b'*';

        let mut wrapped_reader = io::Cursor::new(b64_bytes.clone());
        let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

        // some gymnastics to avoid double-moving the io::Error, which is not Copy
        let read_decode_err = decoder
            .read_to_end(&mut decoded)
            .map_err(|e| {
                let kind = e.kind();
                let inner = e
                    .into_inner()
                    .and_then(|e| e.downcast::<DecodeError>().ok());
                inner.map(|i| (*i, kind))
            })
            .err()
            .and_then(|o| o);

        let mut bulk_buf = Vec::new();
        let bulk_decode_err = decode_engine_vec(&b64_bytes[..], &mut bulk_buf, &engine).err();

        // it's tricky to predict where the invalid data's offset will be since if it's in the last
        // chunk it will be reported at the first padding location because it's treated as invalid
        // padding. So, we just check that it's the same as it is for decoding all at once.
        assert_eq!(
            bulk_decode_err.map(|e| (e, io::ErrorKind::InvalidData)),
            read_decode_err
        );
    }
}

fn consume_with_short_reads_and_validate<R: Read>(
    rng: &mut rand::rngs::ThreadRng,
    expected_bytes: &[u8],
    decoded: &mut Vec<u8>,
    short_reader: &mut R,
) -> () {
    let mut total_read = 0_usize;
    loop {
        assert!(
            total_read <= expected_bytes.len(),
            "tr {} size {}",
            total_read,
            expected_bytes.len()
        );
        if total_read == expected_bytes.len() {
            assert_eq!(expected_bytes, &decoded[..total_read]);
            // should be done
            assert_eq!(0, short_reader.read(&mut decoded[..]).unwrap());
            // didn't write anything
            assert_eq!(expected_bytes, &decoded[..total_read]);

            break;
        }
        let decode_len = rng.gen_range(1, cmp::max(2, expected_bytes.len() * 2));

        let read = short_reader
            .read(&mut decoded[total_read..total_read + decode_len])
            .unwrap();
        total_read += read;
    }
}

/// Limits how many bytes a reader will provide in each read call.
/// Useful for shaking out code that may work fine only with typical input sources that always fill
/// the buffer.
struct RandomShortRead<'a, 'b, R: io::Read, N: rand::Rng> {
    delegate: &'b mut R,
    rng: &'a mut N,
}

impl<'a, 'b, R: io::Read, N: rand::Rng> io::Read for RandomShortRead<'a, 'b, R, N> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        // avoid 0 since it means EOF for non-empty buffers
        let effective_len = cmp::min(self.rng.gen_range(1, 20), buf.len());

        self.delegate.read(&mut buf[..effective_len])
    }
}
<commit_msg>remove unused 'unit' types<commit_after>use std::io::{self, Read};

use rand::{Rng, RngCore};
use std::{cmp, iter};

use super::decoder::{DecoderReader, BUF_SIZE};
use crate::encode::encode_engine_string;
use crate::engine::fast_portable::FastPortable;
use crate::engine::DEFAULT_ENGINE;
use crate::tests::{random_alphabet, random_config, random_engine};
use crate::{decode_engine_vec, DecodeError};

#[test]
fn simple() {
    let tests: &[(&[u8], &[u8])] = &[
        (&b"0"[..], &b"MA=="[..]),
        (b"01", b"MDE="),
        (b"012", b"MDEy"),
        (b"0123", b"MDEyMw=="),
        (b"01234", b"MDEyMzQ="),
        (b"012345", b"MDEyMzQ1"),
        (b"0123456", b"MDEyMzQ1Ng=="),
        (b"01234567", b"MDEyMzQ1Njc="),
        (b"012345678", b"MDEyMzQ1Njc4"),
        (b"0123456789", b"MDEyMzQ1Njc4OQ=="),
    ][..];

    for (text_expected, base64data) in tests.iter() {
        // Read n bytes at a time.
        for n in 1..base64data.len() + 1 {
            let mut wrapped_reader = io::Cursor::new(base64data);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &DEFAULT_ENGINE);

            // handle errors as you normally would
            let mut text_got = Vec::new();
            let mut buffer = vec![0u8; n];
            while let Ok(read) = decoder.read(&mut buffer[..]) {
                if read == 0 {
                    break;
                }
                text_got.extend_from_slice(&buffer[..read]);
            }

            assert_eq!(
                text_got,
                *text_expected,
                "\nGot: {}\nExpected: {}",
                String::from_utf8_lossy(&text_got[..]),
                String::from_utf8_lossy(text_expected)
            );
        }
    }
}

// Make sure we error out on trailing junk.
#[test]
fn trailing_junk() {
    let tests: &[&[u8]] = &[&b"MDEyMzQ1Njc4*!@#$%^&"[..], b"MDEyMzQ1Njc4OQ== "][..];

    for base64data in tests.iter() {
        // Read n bytes at a time.
        for n in 1..base64data.len() + 1 {
            let mut wrapped_reader = io::Cursor::new(base64data);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &DEFAULT_ENGINE);

            // handle errors as you normally would
            let mut buffer = vec![0u8; n];
            let mut saw_error = false;
            loop {
                match decoder.read(&mut buffer[..]) {
                    Err(_) => {
                        saw_error = true;
                        break;
                    }
                    Ok(read) if read == 0 => break,
                    Ok(_) => (),
                }
            }

            assert!(saw_error);
        }
    }
}

#[test]
fn handles_short_read_from_delegate() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        bytes.truncate(size);
        rng.fill_bytes(&mut bytes[..size]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);
        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut wrapped_reader = io::Cursor::new(b64.as_bytes());
        let mut short_reader = RandomShortRead {
            delegate: &mut wrapped_reader,
            rng: &mut rng,
        };

        let mut decoder = DecoderReader::from(&mut short_reader, &engine);

        let decoded_len = decoder.read_to_end(&mut decoded).unwrap();
        assert_eq!(size, decoded_len);
        assert_eq!(&bytes[..], &decoded[..]);
    }
}

#[test]
fn read_in_short_increments() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        // leave room to play around with larger buffers
        decoded.extend(iter::repeat(0).take(size * 3));

        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut wrapped_reader = io::Cursor::new(&b64[..]);
        let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

        consume_with_short_reads_and_validate(&mut rng, &bytes[..], &mut decoded, &mut decoder);
    }
}

#[test]
fn read_in_short_increments_with_short_delegate_reads() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(0, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        // leave room to play around with larger buffers
        decoded.extend(iter::repeat(0).take(size * 3));

        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);

        let mut base_reader = io::Cursor::new(&b64[..]);
        let mut decoder = DecoderReader::from(&mut base_reader, &engine);
        let mut short_reader = RandomShortRead {
            delegate: &mut decoder,
            rng: &mut rand::thread_rng(),
        };

        consume_with_short_reads_and_validate(&mut rng, &bytes[..], &mut decoded, &mut short_reader)
    }
}

#[test]
fn reports_invalid_last_symbol_correctly() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut b64_bytes = Vec::new();
    let mut decoded = Vec::new();
    let mut bulk_decoded = Vec::new();

    for _ in 0..1_000 {
        bytes.clear();
        b64.clear();
        b64_bytes.clear();

        let size = rng.gen_range(1, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        decoded.extend(iter::repeat(0).take(size));
        rng.fill_bytes(&mut bytes[..]);
        assert_eq!(size, bytes.len());

        let config = random_config(&mut rng);
        let alphabet = random_alphabet(&mut rng);
        // changing padding will cause invalid padding errors when we twiddle the last byte
        let engine = FastPortable::from(alphabet, config.with_encode_padding(false));
        encode_engine_string(&bytes[..], &mut b64, &engine);
        b64_bytes.extend(b64.bytes());
        assert_eq!(b64_bytes.len(), b64.len());

        // change the last character to every possible symbol. Should behave the same as bulk
        // decoding whether invalid or valid.
        for &s1 in alphabet.symbols.iter() {
            decoded.clear();
            bulk_decoded.clear();

            // replace the last
            *b64_bytes.last_mut().unwrap() = s1;
            let bulk_res = decode_engine_vec(&b64_bytes[..], &mut bulk_decoded, &engine);

            let mut wrapped_reader = io::Cursor::new(&b64_bytes[..]);
            let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

            let stream_res = decoder.read_to_end(&mut decoded).map(|_| ()).map_err(|e| {
                e.into_inner()
                    .and_then(|e| e.downcast::<DecodeError>().ok())
            });

            assert_eq!(bulk_res.map_err(|e| Some(Box::new(e))), stream_res);
        }
    }
}

#[test]
fn reports_invalid_byte_correctly() {
    let mut rng = rand::thread_rng();
    let mut bytes = Vec::new();
    let mut b64 = String::new();
    let mut decoded = Vec::new();

    for _ in 0..10_000 {
        bytes.clear();
        b64.clear();
        decoded.clear();

        let size = rng.gen_range(1, 10 * BUF_SIZE);
        bytes.extend(iter::repeat(0).take(size));
        rng.fill_bytes(&mut bytes[..size]);
        assert_eq!(size, bytes.len());

        let engine = random_engine(&mut rng);

        encode_engine_string(&bytes[..], &mut b64, &engine);
        // replace one byte, somewhere, with '*', which is invalid
        let bad_byte_pos = rng.gen_range(0, &b64.len());
        let mut b64_bytes = b64.bytes().collect::<Vec<u8>>();
        b64_bytes[bad_byte_pos] = b'*';

        let mut wrapped_reader = io::Cursor::new(b64_bytes.clone());
        let mut decoder = DecoderReader::from(&mut wrapped_reader, &engine);

        // some gymnastics to avoid double-moving the io::Error, which is not Copy
        let read_decode_err = decoder
            .read_to_end(&mut decoded)
            .map_err(|e| {
                let kind = e.kind();
                let inner = e
                    .into_inner()
                    .and_then(|e| e.downcast::<DecodeError>().ok());
                inner.map(|i| (*i, kind))
            })
            .err()
            .and_then(|o| o);

        let mut bulk_buf = Vec::new();
        let bulk_decode_err = decode_engine_vec(&b64_bytes[..], &mut bulk_buf, &engine).err();

        // it's tricky to predict where the invalid data's offset will be since if it's in the last
        // chunk it will be reported at the first padding location because it's treated as invalid
        // padding. So, we just check that it's the same as it is for decoding all at once.
        assert_eq!(
            bulk_decode_err.map(|e| (e, io::ErrorKind::InvalidData)),
            read_decode_err
        );
    }
}

fn consume_with_short_reads_and_validate<R: Read>(
    rng: &mut rand::rngs::ThreadRng,
    expected_bytes: &[u8],
    decoded: &mut Vec<u8>,
    short_reader: &mut R,
) {
    let mut total_read = 0_usize;
    loop {
        assert!(
            total_read <= expected_bytes.len(),
            "tr {} size {}",
            total_read,
            expected_bytes.len()
        );
        if total_read == expected_bytes.len() {
            assert_eq!(expected_bytes, &decoded[..total_read]);
            // should be done
            assert_eq!(0, short_reader.read(&mut decoded[..]).unwrap());
            // didn't write anything
            assert_eq!(expected_bytes, &decoded[..total_read]);

            break;
        }
        let decode_len = rng.gen_range(1, cmp::max(2, expected_bytes.len() * 2));

        let read = short_reader
            .read(&mut decoded[total_read..total_read + decode_len])
            .unwrap();
        total_read += read;
    }
}

/// Limits how many bytes a reader will provide in each read call.
/// Useful for shaking out code that may work fine only with typical input sources that always fill
/// the buffer.
struct RandomShortRead<'a, 'b, R: io::Read, N: rand::Rng> {
    delegate: &'b mut R,
    rng: &'a mut N,
}

impl<'a, 'b, R: io::Read, N: rand::Rng> io::Read for RandomShortRead<'a, 'b, R, N> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        // avoid 0 since it means EOF for non-empty buffers
        let effective_len = cmp::min(self.rng.gen_range(1, 20), buf.len());

        self.delegate.read(&mut buf[..effective_len])
    }
}
<|endoftext|>


<commit_before>//! Handle network connections for a varlink service

#![allow(dead_code)]

use std::net::TcpStream;
#[cfg(unix)]
use std::os::unix::io::IntoRawFd;
#[cfg(unix)]
use std::os::unix::net::UnixStream;
use std::process::Child;

#[cfg(unix)]
use libc::{close, dup2, getpid};
use tempfile::TempDir;
#[cfg(windows)]
use uds_windows::UnixStream;

use crate::error::*;
use crate::stream::Stream;

pub fn varlink_connect<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Box<dyn Stream>, String)> {
    let address = address.as_ref();
    let new_address: String = address.into();

    if new_address.starts_with("tcp:") {
        Ok((
            Box::new(TcpStream::connect(&new_address[4..]).map_err(map_context!())?),
            new_address,
        ))
    } else if new_address.starts_with("unix:") {
        let mut addr = String::from(new_address[5..].split(';').next().unwrap());
        if addr.starts_with('@') {
            addr = addr.replacen('@', "\0", 1);
            return get_abstract_unixstream(&addr)
                .and_then(|v| Ok((Box::new(v) as Box<dyn Stream>, new_address)));
        }
        Ok((
            Box::new(UnixStream::connect(addr).map_err(map_context!())?),
            new_address,
        ))
    } else {
        Err(context!(ErrorKind::InvalidAddress))?
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn get_abstract_unixstream(addr: &str) -> Result<UnixStream> {
    // FIXME: abstract unix domains sockets still not in std
    // FIXME: https://github.com/rust-lang/rust/issues/14194
    use std::os::unix::io::FromRawFd;
    use unix_socket::UnixStream as AbstractStream;

    unsafe {
        Ok(UnixStream::from_raw_fd(
            AbstractStream::connect(addr)
                .map_err(map_context!())?
                .into_raw_fd(),
        ))
    }
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn get_abstract_unixstream(_addr: &str) -> Result<UnixStream> {
    Err(context!(ErrorKind::InvalidAddress))
}

#[cfg(windows)]
pub fn varlink_exec<S: ?Sized + AsRef<str>>(
    _address: &S,
) -> Result<(Child, String, Option<TempDir>)> {
    return Err(context!(ErrorKind::MethodNotImplemented(
        "varlink_exec".into()
    )));
}

#[cfg(unix)]
pub fn varlink_exec<S: ?Sized + AsRef<str>>(
    address: &S,
) -> Result<(Child, String, Option<TempDir>)> {
    use std::env;
    use std::os::unix::process::CommandExt;
    use std::process::Command;
    use tempfile::tempdir;

    let executable = String::from("exec ") + address.as_ref();

    use unix_socket::UnixListener;

    let dir = tempdir().map_err(map_context!())?;
    let file_path = dir.path().join("varlink-socket");

    let listener = UnixListener::bind(file_path.clone()).map_err(map_context!())?;
    let fd = listener.into_raw_fd();

    let child = unsafe {
        Command::new("sh")
            .arg("-c")
            .arg(executable)
            .pre_exec({
                let file_path = file_path.clone();
                move || {
                    dup2(2, 1);
                    if fd != 3 {
                        close(3);
                        dup2(fd, 3);
                    }
                    env::set_var("VARLINK_ADDRESS", format!("unix:{}", file_path.display()));
                    env::set_var("LISTEN_FDS", "1");
                    env::set_var("LISTEN_FDNAMES", "varlink");
                    env::set_var("LISTEN_PID", format!("{}", getpid()));
                    Ok(())
                }
            })
            .spawn()
            .map_err(map_context!())?
    };

    Ok((child, format!("unix:{}", file_path.display()), Some(dir)))
}

#[cfg(windows)]
pub fn varlink_bridge<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Child, Box<dyn Stream>)> {
    use std::io::copy;
    use std::process::{Command, Stdio};
    use std::thread;

    let (stream0, stream1) = UnixStream::pair().map_err(map_context!())?;
    let executable = address.as_ref();

    let mut child = Command::new("cmd")
        .arg("/C")
        .arg(executable)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .map_err(map_context!())?;

    let mut client_writer = child.stdin.take().unwrap();
    let mut client_reader = child.stdout.take().unwrap();
    let mut service_writer = stream1.try_clone().map_err(map_context!())?;
    let mut service_reader = stream1;

    thread::spawn(move || copy(&mut client_reader, &mut service_writer));
    thread::spawn(move || copy(&mut service_reader, &mut client_writer));

    Ok((child, Box::new(stream0)))
}

#[cfg(unix)]
pub fn varlink_bridge<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Child, Box<dyn Stream>)> {
    use std::os::unix::io::FromRawFd;
    use std::process::Command;

    let executable = address.as_ref();
    // use unix_socket::UnixStream;
    let (stream0, stream1) = UnixStream::pair().map_err(map_context!())?;
    let fd = stream1.into_raw_fd();
    let childin = unsafe { ::std::fs::File::from_raw_fd(fd) };
    let childout = unsafe { ::std::fs::File::from_raw_fd(fd) };

    let child = Command::new("sh")
        .arg("-c")
        .arg(executable)
        .stdin(childin)
        .stdout(childout)
        .spawn()
        .map_err(map_context!())?;
    Ok((child, Box::new(stream0)))
}
<commit_msg>varlink/src/client.rs: don't leak FDs in varlink_exec<commit_after>//! Handle network connections for a varlink service

#![allow(dead_code)]

use std::net::TcpStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, IntoRawFd};
#[cfg(unix)]
use std::os::unix::net::UnixStream;
use std::process::Child;

#[cfg(unix)]
use libc::{close, dup2, getpid};
use tempfile::TempDir;
#[cfg(windows)]
use uds_windows::UnixStream;

use crate::error::*;
use crate::stream::Stream;

pub fn varlink_connect<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Box<dyn Stream>, String)> {
    let address = address.as_ref();
    let new_address: String = address.into();

    if new_address.starts_with("tcp:") {
        Ok((
            Box::new(TcpStream::connect(&new_address[4..]).map_err(map_context!())?),
            new_address,
        ))
    } else if new_address.starts_with("unix:") {
        let mut addr = String::from(new_address[5..].split(';').next().unwrap());
        if addr.starts_with('@') {
            addr = addr.replacen('@', "\0", 1);
            return get_abstract_unixstream(&addr)
                .and_then(|v| Ok((Box::new(v) as Box<dyn Stream>, new_address)));
        }
        Ok((
            Box::new(UnixStream::connect(addr).map_err(map_context!())?),
            new_address,
        ))
    } else {
        Err(context!(ErrorKind::InvalidAddress))?
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn get_abstract_unixstream(addr: &str) -> Result<UnixStream> {
    // FIXME: abstract unix domains sockets still not in std
    // FIXME: https://github.com/rust-lang/rust/issues/14194
    use std::os::unix::io::FromRawFd;
    use unix_socket::UnixStream as AbstractStream;

    unsafe {
        Ok(UnixStream::from_raw_fd(
            AbstractStream::connect(addr)
                .map_err(map_context!())?
                .into_raw_fd(),
        ))
    }
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn get_abstract_unixstream(_addr: &str) -> Result<UnixStream> {
    Err(context!(ErrorKind::InvalidAddress))
}

#[cfg(windows)]
pub fn varlink_exec<S: ?Sized + AsRef<str>>(
    _address: &S,
) -> Result<(Child, String, Option<TempDir>)> {
    return Err(context!(ErrorKind::MethodNotImplemented(
        "varlink_exec".into()
    )));
}

#[cfg(unix)]
pub fn varlink_exec<S: ?Sized + AsRef<str>>(
    address: &S,
) -> Result<(Child, String, Option<TempDir>)> {
    use std::env;
    use std::os::unix::process::CommandExt;
    use std::process::Command;
    use tempfile::tempdir;

    let executable = String::from("exec ") + address.as_ref();

    use unix_socket::UnixListener;

    let dir = tempdir().map_err(map_context!())?;
    let file_path = dir.path().join("varlink-socket");

    let listener = UnixListener::bind(file_path.clone()).map_err(map_context!())?;
    let fd = listener.as_raw_fd();

    let child = unsafe {
        Command::new("sh")
            .arg("-c")
            .arg(executable)
            .pre_exec({
                let file_path = file_path.clone();
                move || {
                    dup2(2, 1);
                    if fd != 3 {
                        dup2(fd, 3);
                        close(fd);
                    }
                    env::set_var("VARLINK_ADDRESS", format!("unix:{}", file_path.display()));
                    env::set_var("LISTEN_FDS", "1");
                    env::set_var("LISTEN_FDNAMES", "varlink");
                    env::set_var("LISTEN_PID", format!("{}", getpid()));
                    Ok(())
                }
            })
            .spawn()
            .map_err(map_context!())?
    };

    Ok((child, format!("unix:{}", file_path.display()), Some(dir)))
}

#[cfg(windows)]
pub fn varlink_bridge<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Child, Box<dyn Stream>)> {
    use std::io::copy;
    use std::process::{Command, Stdio};
    use std::thread;

    let (stream0, stream1) = UnixStream::pair().map_err(map_context!())?;
    let executable = address.as_ref();

    let mut child = Command::new("cmd")
        .arg("/C")
        .arg(executable)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .map_err(map_context!())?;

    let mut client_writer = child.stdin.take().unwrap();
    let mut client_reader = child.stdout.take().unwrap();
    let mut service_writer = stream1.try_clone().map_err(map_context!())?;
    let mut service_reader = stream1;

    thread::spawn(move || copy(&mut client_reader, &mut service_writer));
    thread::spawn(move || copy(&mut service_reader, &mut client_writer));

    Ok((child, Box::new(stream0)))
}

#[cfg(unix)]
pub fn varlink_bridge<S: ?Sized + AsRef<str>>(address: &S) -> Result<(Child, Box<dyn Stream>)> {
    use std::os::unix::io::FromRawFd;
    use std::process::Command;

    let executable = address.as_ref();
    // use unix_socket::UnixStream;
    let (stream0, stream1) = UnixStream::pair().map_err(map_context!())?;
    let fd = stream1.into_raw_fd();
    let childin = unsafe { ::std::fs::File::from_raw_fd(fd) };
    let childout = unsafe { ::std::fs::File::from_raw_fd(fd) };

    let child = Command::new("sh")
        .arg("-c")
        .arg(executable)
        .stdin(childin)
        .stdout(childout)
        .spawn()
        .map_err(map_context!())?;
    Ok((child, Box::new(stream0)))
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("RUST TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        )
        .subcommand(
            SubCommand::with_name("probe")
                .about("try to find a package")
                .arg(
                    Arg::with_name("package")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                )
                .arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("package").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match &linkage {
                &"dll" => {
                    remove_vars();
                    env::set_var("VCPKGRS_DYNAMIC", "1");
                }
                &"static" => {
                    remove_vars();
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.find_package(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("  {}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_names.is_empty() {
                    println!("Libraries linking names:");
                    for line in &lib.found_names {
                        println!("  {}", line);
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}

fn remove_vars() {
    env::remove_var("VCPKGRS_DYNAMIC");
    env::remove_var("CARGO_CFG_TARGET_FEATURE");
}
<commit_msg>take a clippy suggestion<commit_after>extern crate clap;
extern crate vcpkg;

use clap::{App, AppSettings, Arg, SubCommand};
use std::env;

fn main() {
    let app = App::new("vcpkg library finder")
        .about("Allows examining what vcpkg will find in a build script")
        .setting(AppSettings::SubcommandRequired)
        .arg(
            Arg::with_name("target")
                .short("t")
                .long("target")
                .value_name("RUST TARGET TRIPLE")
                .help("the rust toolchain triple to find libraries for")
                .takes_value(true)
                .default_value("x86_64-pc-windows-msvc"),
        )
        .subcommand(
            SubCommand::with_name("probe")
                .about("try to find a package")
                .arg(
                    Arg::with_name("package")
                        .index(1)
                        .required(true)
                        .help("probe for a library and display paths and cargo metadata"),
                )
                .arg(
                    Arg::with_name("linkage")
                        .short("l")
                        .long("linkage")
                        .takes_value(true)
                        .possible_values(&["dll", "static"]),
                ),
        );

    let matches = app.get_matches();

    // set TARGET as if we are running under cargo
    env::set_var("TARGET", matches.value_of("target").unwrap());

    if let Some(matches) = matches.subcommand_matches("probe") {
        let lib_name = matches.value_of("package").unwrap();

        let mut cfg = vcpkg::Config::new();
        cfg.cargo_metadata(false);
        cfg.copy_dlls(false);
        if let Some(linkage) = matches.value_of("linkage") {
            match linkage {
                "dll" => {
                    remove_vars();
                    env::set_var("VCPKGRS_DYNAMIC", "1");
                }
                "static" => {
                    remove_vars();
                    env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static");
                }
                _ => unreachable!(),
            }
        }

        match cfg.find_package(lib_name) {
            Ok(lib) => {
                println!("Found library {}", lib_name);

                if !lib.include_paths.is_empty() {
                    println!("Include paths:");
                    for line in &lib.include_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Library paths:");
                    for line in &lib.link_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.link_paths.is_empty() {
                    println!("Runtime Library paths:");
                    for line in &lib.dll_paths {
                        println!("  {}", line.as_os_str().to_str().unwrap());
                    }
                }

                if !lib.cargo_metadata.is_empty() {
                    println!("Cargo metadata:");
                    for line in &lib.cargo_metadata {
                        println!("  {}", line);
                    }
                }
                if !lib.found_dlls.is_empty() {
                    println!("Found DLLs:");
                    for line in &lib.found_dlls {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_libs.is_empty() {
                    println!("Found libs:");
                    for line in &lib.found_libs {
                        println!("  {}", line.display());
                    }
                }
                if !lib.found_names.is_empty() {
                    println!("Libraries linking names:");
                    for line in &lib.found_names {
                        println!("  {}", line);
                    }
                }
            }
            Err(err) => {
                println!("Failed:  {}", err);
            }
        }
    }
}

fn remove_vars() {
    env::remove_var("VCPKGRS_DYNAMIC");
    env::remove_var("CARGO_CFG_TARGET_FEATURE");
}
<|endoftext|>