<commit_before>use std::ops::Range;

use rand;

use scene::ScreenPoint;
use super::Pixel;
use super::utils::to_uniform;
use super::config::SamplerConfig;

#[derive(Clone, Copy)]
pub struct Sample {
    pub pixel: ScreenPoint,
}

pub trait Sampler: Send + Sync {
    fn sample(&self) -> Vec<Sample>;
    fn split(&self, n_parts: u16) -> Vec<Box<Sampler>>;
}

pub struct StratifiedSampler {
    resolution: Pixel,
    range: Range<u32>,
    jitter: bool
}

impl StratifiedSampler {
    pub fn new(resolution: Pixel, config: SamplerConfig) -> StratifiedSampler {
        match config {
            SamplerConfig::Stratified { samples_per_pixel, jitter} =>
                StratifiedSampler {
                    resolution: [resolution[0] * samples_per_pixel,
                                 resolution[1] * samples_per_pixel],
                    range: 0..(resolution[1] * samples_per_pixel),
                    jitter: jitter
                }
        }
    }
}

impl Sampler for StratifiedSampler {
    fn sample(&self) -> Vec<Sample> {
        self.range.clone()
            .flat_map(|x| (0..self.resolution[1]).map(move |y| [x , y]))
            .map(|p| {
                let jitter = if self.jitter {
                    ScreenPoint::new(
                        rand::random::<f64>() % 0.5,
                        rand::random::<f64>() % 0.5)
                } else {
                    ScreenPoint::new(0.0, 0.0)
                };

                Sample {
                    pixel: to_uniform(self.resolution, ScreenPoint::from(p) + jitter)
                }
            }).collect()
    }

    fn split(&self, n_parts: u16) -> Vec<Box<Sampler>> {
        let step_size = self.resolution[0] / n_parts as u32;
        (0..n_parts).map(|i| {
            let start = (i as u32) * step_size;
            let stop = if i == n_parts - 1 {
                self.resolution[0]
            } else {
                start + step_size
            };

            Box::new(StratifiedSampler {
                resolution: self.resolution,
                range: (start..stop),
                jitter: self.jitter}) as Box<Sampler>
        }).collect()
    }
}
<commit_msg>better sampler<commit_after>use std::ops::Range;

use rand;

use scene::ScreenPoint;
use super::Pixel;
use super::utils::to_uniform;
use super::config::SamplerConfig;

#[derive(Clone, Copy)]
pub struct Sample {
    pub pixel: ScreenPoint,
}

pub trait Sampler: Send + Sync {
    fn sample(&self) -> Vec<Sample>;
    fn split(&self, n_parts: u16) -> Vec<Box<Sampler>>;
}

pub struct StratifiedSampler {
    resolution: Pixel,
    range: [Range<u32>; 2],
    jitter: bool
}

impl StratifiedSampler {
    pub fn new(resolution: Pixel, config: SamplerConfig) -> StratifiedSampler {
        match config {
            SamplerConfig::Stratified { samples_per_pixel, jitter} => {
                let width = resolution[0] * samples_per_pixel;
                let height = resolution[1] * samples_per_pixel;
                StratifiedSampler {
                    resolution: [width, height],
                    range: [0..width, 0..height],
                    jitter: jitter
                }
            }
        }
    }

    fn width(&self) -> u32 {
        self.range[0].end - self.range[0].start
    }

    fn height(&self) -> u32 {
        self.range[1].end - self.range[1].start
    }

    fn area(&self) -> u32 {
        self.width() * self.height()
    }
}

impl Sampler for StratifiedSampler {
    fn sample(&self) -> Vec<Sample> {
        let mut result = Vec::with_capacity(self.area() as usize);
        for x in self.range[0].clone() {
            for y in self.range[1].clone() {
                let jitter = if self.jitter {
                    ScreenPoint::new(
                        rand::random::<f64>() % 0.5,
                        rand::random::<f64>() % 0.5)
                } else {
                    ScreenPoint::new(0.0, 0.0)
                };

                result.push(Sample {
                    pixel: to_uniform(self.resolution, ScreenPoint::from([x, y]) + jitter)
                })
            }
        }
        result
    }

    fn split(&self, n_parts: u16) -> Vec<Box<Sampler>> {
        let square_width = (self.area() as f64 / (n_parts as f64)).sqrt() as u32;
        let mut result = Vec::new();
        let mx = self.width() / square_width;
        let my = self.height() / square_width;
        for rx in partition(&self.range[0], mx) {
            for ry in partition(&self.range[1], my) {
                result.push(Box::new(StratifiedSampler {
                    resolution: self.resolution,
                    range: [rx.clone(), ry.clone()],
                    jitter: self.jitter}) as Box<Sampler>)
            }
        }
        result
    }
}

fn partition(r: &Range<u32>, n: u32) -> Vec<Range<u32>> {
    let mut result = Vec::new();
    let step = (r.end - r.start) / n;
    let mut hit_end = false;
    for i in 0..n {
        let start = r.start + step * i;
        let end = if i != n - 1 { r.start + step * (i + 1) } else { r.end };
        assert!(start <= end);
        assert!(r.start <= start);
        assert!(end <= r.end);
        if end == r.end {
            hit_end = true;
        }
        result.push(start..end)
    }
    assert!(hit_end);
    result
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-fast

extern mod extra;

use extra::tempfile;
use std::io::WriterUtil;
use std::io;
use std::os;
use std::uint;

pub fn main() {
    let dir = tempfile::mkdtemp(&Path("."), "").unwrap();
    let path = dir.with_filename("file");

    {
        match io::file_writer(&path, [io::Create, io::Truncate]) {
            Err(ref e) => fail!(e.clone()),
            Ok(f) => {
                for uint::range(0, 1000) |_i| {
                    f.write_u8(0);
                }
            }
        }
    }

    assert!(path.exists());
    assert_eq!(path.get_size(), Some(1000));

    os::remove_dir(&dir);
}
<commit_msg>Fix stat.rs to not pollute the build directory. Closes #6959.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-fast

extern mod extra;

use extra::tempfile;
use std::io::WriterUtil;
use std::io;
use std::os;
use std::uint;

pub fn main() {
    let dir = tempfile::mkdtemp(&Path("."), "").unwrap();
    let path = dir.push("file");

    {
        match io::file_writer(&path, [io::Create, io::Truncate]) {
            Err(ref e) => fail!(e.clone()),
            Ok(f) => {
                for uint::range(0, 1000) |_i| {
                    f.write_u8(0);
                }
            }
        }
    }

    assert!(path.exists());
    assert_eq!(path.get_size(), Some(1000));

    os::remove_file(&path);
    os::remove_dir(&dir);
}
<|endoftext|>


<commit_before>use runtime::Runtime;

/**
 * A function which lets the user provide content by editing a temp files which gets removed after
 * the function got the content from it.
 */
pub fn let_user_provide_content(rt: &Runtime) -> Option<String> {
    use std::io::Read;
    use std::fs::File;
    use std::process::Command;

    let filepath        = "/tmp/imag-tmp.md";
    let file_created    = File::create(filepath)
                                .map(|_| true)
                                .unwrap_or(false);

    if !file_created {
        warn!("Could not create temporary file for user input!");
        return None;
    }

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| {
               child.wait_with_output()
            })
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return None;
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents);
        Some(contents)
    }).unwrap_or(None)
}

/**
 * Edit some content in a temporary file. If anything failes within this routine, it returns the
 * old content and false.
 * If the editing succeeded, it returns the new content and true
 */
pub fn edit_content(rt: &Runtime, old_content: String) -> (String, bool) {
    use std::io::Read;
    use std::io::Write;
    use std::fs::File;
    use std::process::Command;
    use std::process::exit;

    let filepath = "/tmp/imag-tmp.md";
    {
        let mut file = match File::create(filepath) {
            Ok(f) => f,
            Err(e) => {
                error!("Error creating file {}", filepath);
                debug!("Error creating file at '{}', error = {}", filepath, e);
                exit(1);
            }
        };

        file.write(old_content.as_ref())
            .map_err(|e| {
                error!("Error writing content: {}", e);
                debug!("Error writing content: {:?}", e);
                exit(1);
            }).is_ok();
    }
    debug!("Ready with putting old content into the file");

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| child.wait_with_output())
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return (old_content, false);
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents).map_err(|e| {
            error!("Error reading content: {}", e);
            debug!("Error reading content: {:?}", e);
            exit(1);
        }).is_ok();
        (contents, true)
    }).unwrap_or((old_content, false))
}

<commit_msg>Remove unused import<commit_after>use runtime::Runtime;

/**
 * A function which lets the user provide content by editing a temp files which gets removed after
 * the function got the content from it.
 */
pub fn let_user_provide_content(rt: &Runtime) -> Option<String> {
    use std::io::Read;
    use std::fs::File;

    let filepath        = "/tmp/imag-tmp.md";
    let file_created    = File::create(filepath)
                                .map(|_| true)
                                .unwrap_or(false);

    if !file_created {
        warn!("Could not create temporary file for user input!");
        return None;
    }

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| {
               child.wait_with_output()
            })
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return None;
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents);
        Some(contents)
    }).unwrap_or(None)
}

/**
 * Edit some content in a temporary file. If anything failes within this routine, it returns the
 * old content and false.
 * If the editing succeeded, it returns the new content and true
 */
pub fn edit_content(rt: &Runtime, old_content: String) -> (String, bool) {
    use std::io::Read;
    use std::io::Write;
    use std::fs::File;
    use std::process::Command;
    use std::process::exit;

    let filepath = "/tmp/imag-tmp.md";
    {
        let mut file = match File::create(filepath) {
            Ok(f) => f,
            Err(e) => {
                error!("Error creating file {}", filepath);
                debug!("Error creating file at '{}', error = {}", filepath, e);
                exit(1);
            }
        };

        file.write(old_content.as_ref())
            .map_err(|e| {
                error!("Error writing content: {}", e);
                debug!("Error writing content: {:?}", e);
                exit(1);
            }).is_ok();
    }
    debug!("Ready with putting old content into the file");

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| child.wait_with_output())
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return (old_content, false);
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents).map_err(|e| {
            error!("Error reading content: {}", e);
            debug!("Error reading content: {:?}", e);
            exit(1);
        }).is_ok();
        (contents, true)
    }).unwrap_or((old_content, false))
}

<|endoftext|>


<commit_before>extern crate gtk;
use gtk::prelude::*;

extern crate cairo;

use std::rc::Rc;
use std::cell::{Ref, RefCell};

use std::ops::{Deref, DerefMut};

use ::media::Context;

use super::{ImageSurface, MediaController, MediaHandler};

pub struct InfoController {
    media_ctl: MediaController,

    title_lbl: gtk::Label,
    artist_lbl: gtk::Label,
    description_lbl: gtk::Label,
    duration_lbl: gtk::Label,

    chapter_treeview: gtk::TreeView,
    chapter_store: gtk::ListStore,

    thumbnail: Rc<RefCell<Option<ImageSurface>>>,
}

impl InfoController {
    pub fn new(builder: &gtk::Builder) -> Self {
        // need a RefCell because the callbacks will use immutable versions of ac
        // when the UI controllers will get a mutable version from time to time
        let mut ic = InfoController {
            media_ctl: MediaController::new(
                builder.get_object("info-box").unwrap(),
                builder.get_object("thumbnail-drawingarea").unwrap()
            ),

            title_lbl: builder.get_object("title-lbl").unwrap(),
            artist_lbl: builder.get_object("artist-lbl").unwrap(),
            description_lbl: builder.get_object("description-lbl").unwrap(),
            duration_lbl: builder.get_object("duration-lbl").unwrap(),

            chapter_treeview: builder.get_object("chapter-treeview").unwrap(),
            // columns: Id, Title, Start, End
            chapter_store: gtk::ListStore::new(&[gtk::Type::I32, gtk::Type::String, gtk::Type::String, gtk::Type::String]),

            thumbnail: Rc::new(RefCell::new(None)),
        };

        ic.chapter_treeview.set_model(Some(&ic.chapter_store));
        ic.add_chapter_column(&"Id", 0, false);
        ic.add_chapter_column(&"Title", 1, true);
        ic.add_chapter_column(&"Start", 2, false);
        ic.add_chapter_column(&"End", 3, false);

        let thumbnail_weak = Rc::downgrade(&ic.thumbnail);
        ic.draw_handler = ic.drawingarea.connect_draw(move |ref drawing_area, ref cairo_ctx| {
            if let Some(thumbnail_rc) = thumbnail_weak.upgrade() {
                let thumbnail_ref = thumbnail_rc.borrow();
                if let Some(ref thumbnail) = *thumbnail_ref {
                    let surface = &thumbnail.surface;

                    let allocation = drawing_area.get_allocation();
                    let alloc_ratio = allocation.width as f64 / allocation.height as f64;
                    let surface_ratio = surface.get_width() as f64 / surface.get_height() as f64;
                    let scale = if surface_ratio < alloc_ratio {
                        allocation.height as f64 / surface.get_height() as f64
                    }
                    else {
                        allocation.width as f64 / surface.get_width() as f64
                    };
                    let x = (allocation.width as f64 / scale - surface.get_width() as f64).abs() / 2f64;
                    let y = (allocation.height as f64 / scale - surface.get_height() as f64).abs() / 2f64;

                    cairo_ctx.scale(scale, scale);
                    cairo_ctx.set_source_surface(surface, x, y);
                    cairo_ctx.paint();
                }
                else {
                    println!("No thumbnail");
                }
            }
            else {
                println!("Couldn't upgrade");
            }

            Inhibit(false)
        });

        ic
    }

    fn add_chapter_column(&self, title: &str, col_id: i32, can_expand: bool) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);
        let renderer = gtk::CellRendererText::new();
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id);
        col.set_expand(can_expand);
        self.chapter_treeview.append_column(&col);
    }
}

impl Deref for InfoController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for InfoController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaHandler for InfoController {
    fn new_media(&mut self, context: &Context) {
        self.title_lbl.set_label(&context.title);
        self.artist_lbl.set_label(&context.artist);
        self.description_lbl.set_label(&context.description);
        self.duration_lbl.set_label(&format!("{}", context.duration));

        let mut has_image = false;
        if let Some(thumbnail) = context.thumbnail.as_ref() {
            if let Ok(image) = ImageSurface::from_uknown_buffer(thumbnail.as_slice()) {
                let mut thumbnail_ref = self.thumbnail.borrow_mut();
                *thumbnail_ref = Some(image);
                has_image = true;
            }
        };

        if has_image {
            self.drawingarea.show();
            self.drawingarea.queue_draw();
        }
        else {
            self.drawingarea.hide();
        }

        self.chapter_store.clear();
        // FIX for sample.mkv video: generate ids (TODO: remove)
        let mut id = 0;
        for chapter in context.chapters.iter() {
            id += 1;
            self.chapter_store.insert_with_values(
                None, &[0, 1, 2, 3],
                &[&id, &chapter.title(), &format!("{}", &chapter.start), &format!("{}", chapter.end)],
            );
        }
        self.show();
    }
}
<commit_msg>Remove unecessary println (#7)<commit_after>extern crate gtk;
use gtk::prelude::*;

extern crate cairo;

use std::rc::Rc;
use std::cell::{Ref, RefCell};

use std::ops::{Deref, DerefMut};

use ::media::Context;

use super::{ImageSurface, MediaController, MediaHandler};

pub struct InfoController {
    media_ctl: MediaController,

    title_lbl: gtk::Label,
    artist_lbl: gtk::Label,
    description_lbl: gtk::Label,
    duration_lbl: gtk::Label,

    chapter_treeview: gtk::TreeView,
    chapter_store: gtk::ListStore,

    thumbnail: Rc<RefCell<Option<ImageSurface>>>,
}

impl InfoController {
    pub fn new(builder: &gtk::Builder) -> Self {
        // need a RefCell because the callbacks will use immutable versions of ac
        // when the UI controllers will get a mutable version from time to time
        let mut ic = InfoController {
            media_ctl: MediaController::new(
                builder.get_object("info-box").unwrap(),
                builder.get_object("thumbnail-drawingarea").unwrap()
            ),

            title_lbl: builder.get_object("title-lbl").unwrap(),
            artist_lbl: builder.get_object("artist-lbl").unwrap(),
            description_lbl: builder.get_object("description-lbl").unwrap(),
            duration_lbl: builder.get_object("duration-lbl").unwrap(),

            chapter_treeview: builder.get_object("chapter-treeview").unwrap(),
            // columns: Id, Title, Start, End
            chapter_store: gtk::ListStore::new(&[gtk::Type::I32, gtk::Type::String, gtk::Type::String, gtk::Type::String]),

            thumbnail: Rc::new(RefCell::new(None)),
        };

        ic.chapter_treeview.set_model(Some(&ic.chapter_store));
        ic.add_chapter_column(&"Id", 0, false);
        ic.add_chapter_column(&"Title", 1, true);
        ic.add_chapter_column(&"Start", 2, false);
        ic.add_chapter_column(&"End", 3, false);

        let thumbnail_weak = Rc::downgrade(&ic.thumbnail);
        ic.draw_handler = ic.drawingarea.connect_draw(move |ref drawing_area, ref cairo_ctx| {
            if let Some(thumbnail_rc) = thumbnail_weak.upgrade() {
                let thumbnail_ref = thumbnail_rc.borrow();
                if let Some(ref thumbnail) = *thumbnail_ref {
                    let surface = &thumbnail.surface;

                    let allocation = drawing_area.get_allocation();
                    let alloc_ratio = allocation.width as f64 / allocation.height as f64;
                    let surface_ratio = surface.get_width() as f64 / surface.get_height() as f64;
                    let scale = if surface_ratio < alloc_ratio {
                        allocation.height as f64 / surface.get_height() as f64
                    }
                    else {
                        allocation.width as f64 / surface.get_width() as f64
                    };
                    let x = (allocation.width as f64 / scale - surface.get_width() as f64).abs() / 2f64;
                    let y = (allocation.height as f64 / scale - surface.get_height() as f64).abs() / 2f64;

                    cairo_ctx.scale(scale, scale);
                    cairo_ctx.set_source_surface(surface, x, y);
                    cairo_ctx.paint();
                }
            }

            Inhibit(false)
        });

        ic
    }

    fn add_chapter_column(&self, title: &str, col_id: i32, can_expand: bool) {
        let col = gtk::TreeViewColumn::new();
        col.set_title(title);
        let renderer = gtk::CellRendererText::new();
        col.pack_start(&renderer, true);
        col.add_attribute(&renderer, "text", col_id);
        col.set_expand(can_expand);
        self.chapter_treeview.append_column(&col);
    }
}

impl Deref for InfoController {
	type Target = MediaController;

	fn deref(&self) -> &Self::Target {
		&self.media_ctl
	}
}

impl DerefMut for InfoController {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.media_ctl
	}
}

impl MediaHandler for InfoController {
    fn new_media(&mut self, context: &Context) {
        self.title_lbl.set_label(&context.title);
        self.artist_lbl.set_label(&context.artist);
        self.description_lbl.set_label(&context.description);
        self.duration_lbl.set_label(&format!("{}", context.duration));

        let mut has_image = false;
        if let Some(thumbnail) = context.thumbnail.as_ref() {
            if let Ok(image) = ImageSurface::from_uknown_buffer(thumbnail.as_slice()) {
                let mut thumbnail_ref = self.thumbnail.borrow_mut();
                *thumbnail_ref = Some(image);
                has_image = true;
            }
        };

        if has_image {
            self.drawingarea.show();
            self.drawingarea.queue_draw();
        }
        else {
            self.drawingarea.hide();
        }

        self.chapter_store.clear();
        // FIX for sample.mkv video: generate ids (TODO: remove)
        let mut id = 0;
        for chapter in context.chapters.iter() {
            id += 1;
            self.chapter_store.insert_with_values(
                None, &[0, 1, 2, 3],
                &[&id, &chapter.title(), &format!("{}", &chapter.start), &format!("{}", chapter.end)],
            );
        }
        self.show();
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Akira Hayakawa <ruby.wktk@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) PREFIXaa

#[macro_use]
extern crate uucore;

mod platform;

use clap::{crate_version, App, Arg};
use std::convert::TryFrom;
use std::env;
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::{char, fs::remove_file};
use uucore::display::Quotable;
use uucore::parse_size::parse_size;

static OPT_BYTES: &str = "bytes";
static OPT_LINE_BYTES: &str = "line-bytes";
static OPT_LINES: &str = "lines";
static OPT_ADDITIONAL_SUFFIX: &str = "additional-suffix";
static OPT_FILTER: &str = "filter";
static OPT_NUMERIC_SUFFIXES: &str = "numeric-suffixes";
static OPT_SUFFIX_LENGTH: &str = "suffix-length";
static OPT_DEFAULT_SUFFIX_LENGTH: &str = "2";
static OPT_VERBOSE: &str = "verbose";

static ARG_INPUT: &str = "input";
static ARG_PREFIX: &str = "prefix";

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [PREFIX]]",
        uucore::execution_phrase()
    )
}
fn get_long_usage() -> String {
    format!(
        "Usage:
  {0}

Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
-, read standard input.",
        usage()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let mut settings = Settings {
        prefix: "".to_owned(),
        numeric_suffix: false,
        suffix_length: 0,
        additional_suffix: "".to_owned(),
        input: "".to_owned(),
        filter: None,
        strategy: "".to_owned(),
        strategy_param: "".to_owned(),
        verbose: false,
    };

    settings.suffix_length = matches
        .value_of(OPT_SUFFIX_LENGTH)
        .unwrap()
        .parse()
        .unwrap_or_else(|_| panic!("Invalid number for {}", OPT_SUFFIX_LENGTH));

    settings.numeric_suffix = matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0;
    settings.additional_suffix = matches.value_of(OPT_ADDITIONAL_SUFFIX).unwrap().to_owned();

    settings.verbose = matches.occurrences_of("verbose") > 0;
    // check that the user is not specifying more than one strategy
    // note: right now, this exact behavior cannot be handled by ArgGroup since ArgGroup
    // considers a default value Arg as "defined"
    let explicit_strategies =
        vec![OPT_LINE_BYTES, OPT_LINES, OPT_BYTES]
            .into_iter()
            .fold(0, |count, strategy| {
                if matches.occurrences_of(strategy) > 0 {
                    count + 1
                } else {
                    count
                }
            });
    if explicit_strategies > 1 {
        crash!(1, "cannot split in more than one way");
    }

    // default strategy (if no strategy is passed, use this one)
    settings.strategy = String::from(OPT_LINES);
    settings.strategy_param = matches.value_of(OPT_LINES).unwrap().to_owned();
    // take any (other) defined strategy
    for &strategy in &[OPT_LINE_BYTES, OPT_BYTES] {
        if matches.occurrences_of(strategy) > 0 {
            settings.strategy = String::from(strategy);
            settings.strategy_param = matches.value_of(strategy).unwrap().to_owned();
        }
    }

    settings.input = matches.value_of(ARG_INPUT).unwrap().to_owned();
    settings.prefix = matches.value_of(ARG_PREFIX).unwrap().to_owned();

    if matches.occurrences_of(OPT_FILTER) > 0 {
        if cfg!(windows) {
            // see https://github.com/rust-lang/rust/issues/29494
            show_error!("{} is currently not supported in this platform", OPT_FILTER);
            exit!(-1);
        } else {
            settings.filter = Some(matches.value_of(OPT_FILTER).unwrap().to_owned());
        }
    }

    split(&settings)
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about("Create output files containing consecutive or interleaved sections of input")
        // strategy (mutually exclusive)
        .arg(
            Arg::with_name(OPT_BYTES)
                .short("b")
                .long(OPT_BYTES)
                .takes_value(true)
                .default_value("2")
                .help("use suffixes of length N (default 2)"),
        )
        .arg(
            Arg::with_name(OPT_LINE_BYTES)
                .short("C")
                .long(OPT_LINE_BYTES)
                .takes_value(true)
                .default_value("2")
                .help("put at most SIZE bytes of lines per output file"),
        )
        .arg(
            Arg::with_name(OPT_LINES)
                .short("l")
                .long(OPT_LINES)
                .takes_value(true)
                .default_value("1000")
                .help("put NUMBER lines/records per output file"),
        )
        // rest of the arguments
        .arg(
            Arg::with_name(OPT_ADDITIONAL_SUFFIX)
                .long(OPT_ADDITIONAL_SUFFIX)
                .takes_value(true)
                .default_value("")
                .help("additional suffix to append to output file names"),
        )
        .arg(
            Arg::with_name(OPT_FILTER)
                .long(OPT_FILTER)
                .takes_value(true)
                .help("write to shell COMMAND file name is $FILE (Currently not implemented for Windows)"),
        )
        .arg(
            Arg::with_name(OPT_NUMERIC_SUFFIXES)
                .short("d")
                .long(OPT_NUMERIC_SUFFIXES)
                .takes_value(true)
                .default_value("0")
                .help("use numeric suffixes instead of alphabetic"),
        )
        .arg(
            Arg::with_name(OPT_SUFFIX_LENGTH)
                .short("a")
                .long(OPT_SUFFIX_LENGTH)
                .takes_value(true)
                .default_value(OPT_DEFAULT_SUFFIX_LENGTH)
                .help("use suffixes of length N (default 2)"),
        )
        .arg(
            Arg::with_name(OPT_VERBOSE)
                .long(OPT_VERBOSE)
                .help("print a diagnostic just before each output file is opened"),
        )
        .arg(
            Arg::with_name(ARG_INPUT)
            .takes_value(true)
            .default_value("-")
            .index(1)
        )
        .arg(
            Arg::with_name(ARG_PREFIX)
            .takes_value(true)
            .default_value("x")
            .index(2)
        )
}

#[allow(dead_code)]
struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: usize,
    additional_suffix: String,
    input: String,
    /// When supplied, a shell command to output to instead of xaa, xab …
    filter: Option<String>,
    strategy: String,
    strategy_param: String,
    verbose: bool, // TODO: warning: field is never read: `verbose`
}

trait Splitter {
    // Consume as much as possible from `reader` so as to saturate `writer`.
    // Equivalent to finishing one of the part files. Returns the number of
    // bytes that have been moved.
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128;
}

struct LineSplitter {
    lines_per_split: usize,
}

impl LineSplitter {
    fn new(settings: &Settings) -> LineSplitter {
        LineSplitter {
            lines_per_split: settings.strategy_param.parse().unwrap_or_else(|_| {
                crash!(
                    1,
                    "invalid number of lines: {}",
                    settings.strategy_param.quote()
                )
            }),
        }
    }
}

impl Splitter for LineSplitter {
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128 {
        let mut bytes_consumed = 0u128;
        let mut buffer = String::with_capacity(1024);
        for _ in 0..self.lines_per_split {
            let bytes_read = reader
                .read_line(&mut buffer)
                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
            // If we ever read 0 bytes then we know we've hit EOF.
            if bytes_read == 0 {
                return bytes_consumed;
            }

            writer
                .write_all(buffer.as_bytes())
                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));
            // Empty out the String buffer since `read_line` appends instead of
            // replaces.
            buffer.clear();

            bytes_consumed += bytes_read as u128;
        }

        bytes_consumed
    }
}

struct ByteSplitter {
    bytes_per_split: u128,
}

impl ByteSplitter {
    fn new(settings: &Settings) -> ByteSplitter {
        let size_string = &settings.strategy_param;
        let size_num = match parse_size(size_string) {
            Ok(n) => n,
            Err(e) => crash!(1, "invalid number of bytes: {}", e.to_string()),
        };

        ByteSplitter {
            bytes_per_split: u128::try_from(size_num).unwrap(),
        }
    }
}

impl Splitter for ByteSplitter {
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128 {
        // We buffer reads and writes. We proceed until `bytes_consumed` is
        // equal to `self.bytes_per_split` or we reach EOF.
        let mut bytes_consumed = 0u128;
        const BUFFER_SIZE: usize = 1024;
        let mut buffer = [0u8; BUFFER_SIZE];
        while bytes_consumed < self.bytes_per_split {
            // Don't overshoot `self.bytes_per_split`! Note: Using std::cmp::min
            // doesn't really work since we have to get types to match which
            // can't be done in a way that keeps all conversions safe.
            let bytes_desired = if (BUFFER_SIZE as u128) <= self.bytes_per_split - bytes_consumed {
                BUFFER_SIZE
            } else {
                // This is a safe conversion since the difference must be less
                // than BUFFER_SIZE in this branch.
                (self.bytes_per_split - bytes_consumed) as usize
            };
            let bytes_read = reader
                .read(&mut buffer[0..bytes_desired])
                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
            // If we ever read 0 bytes then we know we've hit EOF.
            if bytes_read == 0 {
                return bytes_consumed;
            }

            writer
                .write_all(&buffer[0..bytes_read])
                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));

            bytes_consumed += bytes_read as u128;
        }

        bytes_consumed
    }
}

// (1, 3) -> "aab"
#[allow(clippy::many_single_char_names)]
fn str_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 26usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
#[allow(clippy::many_single_char_names)]
fn num_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 10usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r as u32, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> i32 {
    let mut reader = BufReader::new(if settings.input == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let r = File::open(Path::new(&settings.input)).unwrap_or_else(|_| {
            crash!(
                1,
                "cannot open {} for reading: No such file or directory",
                settings.input.quote()
            )
        });
        Box::new(r) as Box<dyn Read>
    });

    let mut splitter: Box<dyn Splitter> = match settings.strategy.as_str() {
        s if s == OPT_LINES => Box::new(LineSplitter::new(settings)),
        s if (s == OPT_BYTES || s == OPT_LINE_BYTES) => Box::new(ByteSplitter::new(settings)),
        a => crash!(1, "strategy {} not supported", a.quote()),
    };

    let mut fileno = 0;
    loop {
        // Get a new part file set up, and construct `writer` for it.
        let mut filename = settings.prefix.clone();
        filename.push_str(
            if settings.numeric_suffix {
                num_prefix(fileno, settings.suffix_length)
            } else {
                str_prefix(fileno, settings.suffix_length)
            }
            .as_ref(),
        );
        filename.push_str(settings.additional_suffix.as_ref());
        let mut writer = platform::instantiate_current_writer(&settings.filter, filename.as_str());

        let bytes_consumed = splitter.consume(&mut reader, &mut writer);
        writer
            .flush()
            .unwrap_or_else(|e| crash!(1, "error flushing to output file: {}", e));

        // If we didn't write anything we should clean up the empty file, and
        // break from the loop.
        if bytes_consumed == 0 {
            // The output file is only ever created if --filter isn't used.
            // Complicated, I know...
            if settings.filter.is_none() {
                remove_file(filename)
                    .unwrap_or_else(|e| crash!(1, "error removing empty file: {}", e));
            }
            break;
        }

        fileno += 1;
    }
    0
}
<commit_msg>split: move parsing outside of *Splitter::new()<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Akira Hayakawa <ruby.wktk@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) PREFIXaa

#[macro_use]
extern crate uucore;

mod platform;

use clap::{crate_version, App, Arg};
use std::convert::TryFrom;
use std::env;
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path;
use std::{char, fs::remove_file};
use uucore::display::Quotable;
use uucore::parse_size::parse_size;

static OPT_BYTES: &str = "bytes";
static OPT_LINE_BYTES: &str = "line-bytes";
static OPT_LINES: &str = "lines";
static OPT_ADDITIONAL_SUFFIX: &str = "additional-suffix";
static OPT_FILTER: &str = "filter";
static OPT_NUMERIC_SUFFIXES: &str = "numeric-suffixes";
static OPT_SUFFIX_LENGTH: &str = "suffix-length";
static OPT_DEFAULT_SUFFIX_LENGTH: &str = "2";
static OPT_VERBOSE: &str = "verbose";

static ARG_INPUT: &str = "input";
static ARG_PREFIX: &str = "prefix";

fn usage() -> String {
    format!(
        "{0} [OPTION]... [INPUT [PREFIX]]",
        uucore::execution_phrase()
    )
}
fn get_long_usage() -> String {
    format!(
        "Usage:
  {0}

Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
-, read standard input.",
        usage()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();
    let long_usage = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&long_usage[..])
        .get_matches_from(args);

    let mut settings = Settings {
        prefix: "".to_owned(),
        numeric_suffix: false,
        suffix_length: 0,
        additional_suffix: "".to_owned(),
        input: "".to_owned(),
        filter: None,
        strategy: "".to_owned(),
        strategy_param: "".to_owned(),
        verbose: false,
    };

    settings.suffix_length = matches
        .value_of(OPT_SUFFIX_LENGTH)
        .unwrap()
        .parse()
        .unwrap_or_else(|_| panic!("Invalid number for {}", OPT_SUFFIX_LENGTH));

    settings.numeric_suffix = matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0;
    settings.additional_suffix = matches.value_of(OPT_ADDITIONAL_SUFFIX).unwrap().to_owned();

    settings.verbose = matches.occurrences_of("verbose") > 0;
    // check that the user is not specifying more than one strategy
    // note: right now, this exact behavior cannot be handled by ArgGroup since ArgGroup
    // considers a default value Arg as "defined"
    let explicit_strategies =
        vec![OPT_LINE_BYTES, OPT_LINES, OPT_BYTES]
            .into_iter()
            .fold(0, |count, strategy| {
                if matches.occurrences_of(strategy) > 0 {
                    count + 1
                } else {
                    count
                }
            });
    if explicit_strategies > 1 {
        crash!(1, "cannot split in more than one way");
    }

    // default strategy (if no strategy is passed, use this one)
    settings.strategy = String::from(OPT_LINES);
    settings.strategy_param = matches.value_of(OPT_LINES).unwrap().to_owned();
    // take any (other) defined strategy
    for &strategy in &[OPT_LINE_BYTES, OPT_BYTES] {
        if matches.occurrences_of(strategy) > 0 {
            settings.strategy = String::from(strategy);
            settings.strategy_param = matches.value_of(strategy).unwrap().to_owned();
        }
    }

    settings.input = matches.value_of(ARG_INPUT).unwrap().to_owned();
    settings.prefix = matches.value_of(ARG_PREFIX).unwrap().to_owned();

    if matches.occurrences_of(OPT_FILTER) > 0 {
        if cfg!(windows) {
            // see https://github.com/rust-lang/rust/issues/29494
            show_error!("{} is currently not supported in this platform", OPT_FILTER);
            exit!(-1);
        } else {
            settings.filter = Some(matches.value_of(OPT_FILTER).unwrap().to_owned());
        }
    }

    split(&settings)
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about("Create output files containing consecutive or interleaved sections of input")
        // strategy (mutually exclusive)
        .arg(
            Arg::with_name(OPT_BYTES)
                .short("b")
                .long(OPT_BYTES)
                .takes_value(true)
                .default_value("2")
                .help("use suffixes of length N (default 2)"),
        )
        .arg(
            Arg::with_name(OPT_LINE_BYTES)
                .short("C")
                .long(OPT_LINE_BYTES)
                .takes_value(true)
                .default_value("2")
                .help("put at most SIZE bytes of lines per output file"),
        )
        .arg(
            Arg::with_name(OPT_LINES)
                .short("l")
                .long(OPT_LINES)
                .takes_value(true)
                .default_value("1000")
                .help("put NUMBER lines/records per output file"),
        )
        // rest of the arguments
        .arg(
            Arg::with_name(OPT_ADDITIONAL_SUFFIX)
                .long(OPT_ADDITIONAL_SUFFIX)
                .takes_value(true)
                .default_value("")
                .help("additional suffix to append to output file names"),
        )
        .arg(
            Arg::with_name(OPT_FILTER)
                .long(OPT_FILTER)
                .takes_value(true)
                .help("write to shell COMMAND file name is $FILE (Currently not implemented for Windows)"),
        )
        .arg(
            Arg::with_name(OPT_NUMERIC_SUFFIXES)
                .short("d")
                .long(OPT_NUMERIC_SUFFIXES)
                .takes_value(true)
                .default_value("0")
                .help("use numeric suffixes instead of alphabetic"),
        )
        .arg(
            Arg::with_name(OPT_SUFFIX_LENGTH)
                .short("a")
                .long(OPT_SUFFIX_LENGTH)
                .takes_value(true)
                .default_value(OPT_DEFAULT_SUFFIX_LENGTH)
                .help("use suffixes of length N (default 2)"),
        )
        .arg(
            Arg::with_name(OPT_VERBOSE)
                .long(OPT_VERBOSE)
                .help("print a diagnostic just before each output file is opened"),
        )
        .arg(
            Arg::with_name(ARG_INPUT)
            .takes_value(true)
            .default_value("-")
            .index(1)
        )
        .arg(
            Arg::with_name(ARG_PREFIX)
            .takes_value(true)
            .default_value("x")
            .index(2)
        )
}

#[allow(dead_code)]
struct Settings {
    prefix: String,
    numeric_suffix: bool,
    suffix_length: usize,
    additional_suffix: String,
    input: String,
    /// When supplied, a shell command to output to instead of xaa, xab …
    filter: Option<String>,
    strategy: String,
    strategy_param: String,
    verbose: bool, // TODO: warning: field is never read: `verbose`
}

trait Splitter {
    // Consume as much as possible from `reader` so as to saturate `writer`.
    // Equivalent to finishing one of the part files. Returns the number of
    // bytes that have been moved.
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128;
}

struct LineSplitter {
    lines_per_split: usize,
}

impl LineSplitter {
    fn new(chunk_size: usize) -> LineSplitter {
        LineSplitter {
            lines_per_split: chunk_size,
        }
    }
}

impl Splitter for LineSplitter {
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128 {
        let mut bytes_consumed = 0u128;
        let mut buffer = String::with_capacity(1024);
        for _ in 0..self.lines_per_split {
            let bytes_read = reader
                .read_line(&mut buffer)
                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
            // If we ever read 0 bytes then we know we've hit EOF.
            if bytes_read == 0 {
                return bytes_consumed;
            }

            writer
                .write_all(buffer.as_bytes())
                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));
            // Empty out the String buffer since `read_line` appends instead of
            // replaces.
            buffer.clear();

            bytes_consumed += bytes_read as u128;
        }

        bytes_consumed
    }
}

struct ByteSplitter {
    bytes_per_split: u128,
}

impl ByteSplitter {
    fn new(chunk_size: usize) -> ByteSplitter {
        ByteSplitter {
            bytes_per_split: u128::try_from(chunk_size).unwrap(),
        }
    }
}

impl Splitter for ByteSplitter {
    fn consume(
        &mut self,
        reader: &mut BufReader<Box<dyn Read>>,
        writer: &mut BufWriter<Box<dyn Write>>,
    ) -> u128 {
        // We buffer reads and writes. We proceed until `bytes_consumed` is
        // equal to `self.bytes_per_split` or we reach EOF.
        let mut bytes_consumed = 0u128;
        const BUFFER_SIZE: usize = 1024;
        let mut buffer = [0u8; BUFFER_SIZE];
        while bytes_consumed < self.bytes_per_split {
            // Don't overshoot `self.bytes_per_split`! Note: Using std::cmp::min
            // doesn't really work since we have to get types to match which
            // can't be done in a way that keeps all conversions safe.
            let bytes_desired = if (BUFFER_SIZE as u128) <= self.bytes_per_split - bytes_consumed {
                BUFFER_SIZE
            } else {
                // This is a safe conversion since the difference must be less
                // than BUFFER_SIZE in this branch.
                (self.bytes_per_split - bytes_consumed) as usize
            };
            let bytes_read = reader
                .read(&mut buffer[0..bytes_desired])
                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
            // If we ever read 0 bytes then we know we've hit EOF.
            if bytes_read == 0 {
                return bytes_consumed;
            }

            writer
                .write_all(&buffer[0..bytes_read])
                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));

            bytes_consumed += bytes_read as u128;
        }

        bytes_consumed
    }
}

// (1, 3) -> "aab"
#[allow(clippy::many_single_char_names)]
fn str_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 26usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_u32((r as u32) + 97).unwrap());
    }
    c
}

// (1, 3) -> "001"
#[allow(clippy::many_single_char_names)]
fn num_prefix(i: usize, width: usize) -> String {
    let mut c = "".to_owned();
    let mut n = i;
    let mut w = width;
    while w > 0 {
        w -= 1;
        let div = 10usize.pow(w as u32);
        let r = n / div;
        n -= r * div;
        c.push(char::from_digit(r as u32, 10).unwrap());
    }
    c
}

fn split(settings: &Settings) -> i32 {
    let mut reader = BufReader::new(if settings.input == "-" {
        Box::new(stdin()) as Box<dyn Read>
    } else {
        let r = File::open(Path::new(&settings.input)).unwrap_or_else(|_| {
            crash!(
                1,
                "cannot open {} for reading: No such file or directory",
                settings.input.quote()
            )
        });
        Box::new(r) as Box<dyn Read>
    });

    let size_string = &settings.strategy_param;
    let chunk_size = match parse_size(size_string) {
        Ok(n) => n,
        Err(e) => {
            let option_type = if settings.strategy == OPT_LINES {
                "lines"
            } else {
                "bytes"
            };
            crash!(1, "invalid number of {}: {}", option_type, e.to_string())
        }
    };

    let mut splitter: Box<dyn Splitter> = match settings.strategy.as_str() {
        s if s == OPT_LINES => Box::new(LineSplitter::new(chunk_size)),
        s if (s == OPT_BYTES || s == OPT_LINE_BYTES) => Box::new(ByteSplitter::new(chunk_size)),
        a => crash!(1, "strategy {} not supported", a.quote()),
    };

    let mut fileno = 0;
    loop {
        // Get a new part file set up, and construct `writer` for it.
        let mut filename = settings.prefix.clone();
        filename.push_str(
            if settings.numeric_suffix {
                num_prefix(fileno, settings.suffix_length)
            } else {
                str_prefix(fileno, settings.suffix_length)
            }
            .as_ref(),
        );
        filename.push_str(settings.additional_suffix.as_ref());
        let mut writer = platform::instantiate_current_writer(&settings.filter, filename.as_str());

        let bytes_consumed = splitter.consume(&mut reader, &mut writer);
        writer
            .flush()
            .unwrap_or_else(|e| crash!(1, "error flushing to output file: {}", e));

        // If we didn't write anything we should clean up the empty file, and
        // break from the loop.
        if bytes_consumed == 0 {
            // The output file is only ever created if --filter isn't used.
            // Complicated, I know...
            if settings.filter.is_none() {
                remove_file(filename)
                    .unwrap_or_else(|e| crash!(1, "error removing empty file: {}", e));
            }
            break;
        }

        fileno += 1;
    }
    0
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

extern crate clap;
extern crate platform_info;
#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use platform_info::*;

const VERSION: &str = env!("CARGO_PKG_VERSION");
const ABOUT: &str = "Print certain system information.  With no OPTION, same as -s.";

const OPT_ALL: &str = "all";
const OPT_KERNELNAME: &str = "kernel-name";
const OPT_NODENAME: &str = "nodename";
const OPT_KERNELVERSION: &str = "kernel-version";
const OPT_KERNELRELEASE: &str = "kernel-release";
const OPT_MACHINE: &str = "machine";

//FIXME: unimplemented options
//const OPT_PROCESSOR: &'static str = "processor";
//const OPT_HWPLATFORM: &'static str = "hardware-platform";
const OPT_OS: &str = "operating-system";

#[cfg(target_os = "linux")]
const HOST_OS: &str = "GNU/Linux";
#[cfg(target_os = "windows")]
const HOST_OS: &str = "Windows NT";
#[cfg(target_os = "freebsd")]
const HOST_OS: &str = "FreeBSD";
#[cfg(target_os = "openbsd")]
const HOST_OS: &str = "OpenBSD";
#[cfg(target_os = "macos")]
const HOST_OS: &str = "Darwin";
#[cfg(target_os = "fuchsia")]
const HOST_OS: &str = "Fuchsia";
#[cfg(target_os = "redox")]
const HOST_OS: &str = "Redox";

pub fn uumain(args: Vec<String>) -> i32 {
    let usage = format!("{} [OPTION]...", executable!());
    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(Arg::with_name(OPT_ALL)
            .short("a")
            .long(OPT_ALL)
            .help("Behave as though all of the options -mnrsv were specified."))
        .arg(Arg::with_name(OPT_KERNELNAME)
            .short("s")
            .long(OPT_KERNELNAME)
            .alias("sysname") // Obsolescent option in GNU uname
            .help("print the operating system name."))
        .arg(Arg::with_name(OPT_NODENAME)
            .short("n")
            .long(OPT_NODENAME)
            .help("print the nodename (the nodename may be a name that the system is known by to a communications network)."))
        .arg(Arg::with_name(OPT_KERNELRELEASE)
            .short("r")
            .long(OPT_KERNELRELEASE)
            .alias("release") // Obsolescent option in GNU uname
            .help("print the operating system release."))
        .arg(Arg::with_name(OPT_KERNELVERSION)
            .short("v")
            .long(OPT_KERNELVERSION)
            .help("print the operating system version."))

        //FIXME: unimplemented options
        // .arg(Arg::with_name(OPT_PROCESSOR)
        //     .short("p")
        //     .long(OPT_PROCESSOR)
        //     .help("print the processor type (non-portable)"))
        // .arg(Arg::with_name(OPT_HWPLATFORM)
        //     .short("i")
        //     .long(OPT_HWPLATFORM)
        //     .help("print the hardware platform (non-portable)"))
        .arg(Arg::with_name(OPT_MACHINE)
            .short("m")
            .long(OPT_MACHINE)
            .help("print the machine hardware name."))
        .get_matches_from(&args);

    let argc = args.len();
    let uname = return_if_err!(1, PlatformInfo::new());
    let mut output = String::new();

    if matches.is_present(OPT_KERNELNAME) || matches.is_present(OPT_ALL) || argc == 1 {
        output.push_str(&uname.sysname());
        output.push_str(" ");
    }

    if matches.is_present(OPT_NODENAME) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.nodename());
        output.push_str(" ");
    }
    if matches.is_present(OPT_KERNELRELEASE) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.release());
        output.push_str(" ");
    }
    if matches.is_present(OPT_KERNELVERSION) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.version());
        output.push_str(" ");
    }
    if matches.is_present(OPT_MACHINE) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.machine());
        output.push_str(" ");
    }
    if matches.is_present(OPT_OS) || matches.is_present(OPT_ALL) {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim_end());

    0
}
<commit_msg>feature(uname): Add -o/--operating-system flag<commit_after>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

extern crate clap;
extern crate platform_info;
#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use platform_info::*;

const VERSION: &str = env!("CARGO_PKG_VERSION");
const ABOUT: &str = "Print certain system information.  With no OPTION, same as -s.";

const OPT_ALL: &str = "all";
const OPT_KERNELNAME: &str = "kernel-name";
const OPT_NODENAME: &str = "nodename";
const OPT_KERNELVERSION: &str = "kernel-version";
const OPT_KERNELRELEASE: &str = "kernel-release";
const OPT_MACHINE: &str = "machine";

//FIXME: unimplemented options
//const OPT_PROCESSOR: &'static str = "processor";
//const OPT_HWPLATFORM: &'static str = "hardware-platform";
const OPT_OS: &str = "operating-system";

#[cfg(target_os = "linux")]
const HOST_OS: &str = "GNU/Linux";
#[cfg(target_os = "windows")]
const HOST_OS: &str = "Windows NT";
#[cfg(target_os = "freebsd")]
const HOST_OS: &str = "FreeBSD";
#[cfg(target_os = "openbsd")]
const HOST_OS: &str = "OpenBSD";
#[cfg(target_os = "macos")]
const HOST_OS: &str = "Darwin";
#[cfg(target_os = "fuchsia")]
const HOST_OS: &str = "Fuchsia";
#[cfg(target_os = "redox")]
const HOST_OS: &str = "Redox";

pub fn uumain(args: Vec<String>) -> i32 {
    let usage = format!("{} [OPTION]...", executable!());
    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(Arg::with_name(OPT_ALL)
            .short("a")
            .long(OPT_ALL)
            .help("Behave as though all of the options -mnrsv were specified."))
        .arg(Arg::with_name(OPT_KERNELNAME)
            .short("s")
            .long(OPT_KERNELNAME)
            .alias("sysname") // Obsolescent option in GNU uname
            .help("print the kernel name."))
        .arg(Arg::with_name(OPT_NODENAME)
            .short("n")
            .long(OPT_NODENAME)
            .help("print the nodename (the nodename may be a name that the system is known by to a communications network)."))
        .arg(Arg::with_name(OPT_KERNELRELEASE)
            .short("r")
            .long(OPT_KERNELRELEASE)
            .alias("release") // Obsolescent option in GNU uname
            .help("print the operating system release."))
        .arg(Arg::with_name(OPT_KERNELVERSION)
            .short("v")
            .long(OPT_KERNELVERSION)
            .help("print the operating system version."))

        //FIXME: unimplemented options
        // .arg(Arg::with_name(OPT_PROCESSOR)
        //     .short("p")
        //     .long(OPT_PROCESSOR)
        //     .help("print the processor type (non-portable)"))
        // .arg(Arg::with_name(OPT_HWPLATFORM)
        //     .short("i")
        //     .long(OPT_HWPLATFORM)
        //     .help("print the hardware platform (non-portable)"))
        .arg(Arg::with_name(OPT_MACHINE)
            .short("m")
            .long(OPT_MACHINE)
            .help("print the machine hardware name."))
        .arg(Arg::with_name(OPT_OS)
            .short("o")
            .long(OPT_OS)
            .help("print the operating system name."))
        .get_matches_from(&args);

    let argc = args.len();
    let uname = return_if_err!(1, PlatformInfo::new());
    let mut output = String::new();

    if matches.is_present(OPT_KERNELNAME) || matches.is_present(OPT_ALL) || argc == 1 {
        output.push_str(&uname.sysname());
        output.push_str(" ");
    }

    if matches.is_present(OPT_NODENAME) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.nodename());
        output.push_str(" ");
    }
    if matches.is_present(OPT_KERNELRELEASE) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.release());
        output.push_str(" ");
    }
    if matches.is_present(OPT_KERNELVERSION) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.version());
        output.push_str(" ");
    }
    if matches.is_present(OPT_MACHINE) || matches.is_present(OPT_ALL) {
        output.push_str(&uname.machine());
        output.push_str(" ");
    }
    if matches.is_present(OPT_OS) || matches.is_present(OPT_ALL) {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim_end());

    0
}
<|endoftext|>


<commit_before>extern crate rsoundio;

#[test]
fn test_soundio() {
    let sio = rsoundio::SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.backend(0).is_some());
    assert!(sio.backend(-1).is_none());
    sio.connect().unwrap();
    sio.disconnect();
    if sio.have_backend(rsoundio::SioBackend::Alsa) {
        sio.connect_backend(rsoundio::SioBackend::Alsa)
           .unwrap();
        sio.disconnect();
    }
    assert!(rsoundio::SoundIo::channel_layout_builtin_count() >= 0);
    sio.connect().unwrap();
    sio.flush_events();
    assert!(sio.output_device_count().unwrap() > 0);
    assert!(sio.input_device_count().unwrap() > 0);
}

#[test]
fn test_channel_layout() {
    let cnt = rsoundio::SoundIo::channel_layout_builtin_count();
    assert!(cnt > 0);
    assert!(rsoundio::ChannelLayout::builtin(-1).is_none());
    assert_eq!(rsoundio::ChannelLayout::builtin(0),
               rsoundio::ChannelLayout::builtin(0));
    let mut layout = rsoundio::ChannelLayout::default(2).unwrap();
    assert!(layout.detect_builtin());
    assert!(layout.find_channel(rsoundio::SioChannelId::FrontLeft)
                  .is_some());
    assert!(layout.find_channel(rsoundio::SioChannelId::Lfe2)
                  .is_none());
    assert!(cnt > 2);
    let preferred = [rsoundio::ChannelLayout::builtin(0).unwrap(),
                     rsoundio::ChannelLayout::builtin(1).unwrap()];
    let available = [rsoundio::ChannelLayout::builtin(1).unwrap(),
                     rsoundio::ChannelLayout::builtin(2).unwrap()];
    let best_match = rsoundio::ChannelLayout::best_matching_channel_layout(&preferred, &available);
    assert_eq!(rsoundio::ChannelLayout::builtin(1).unwrap(),
               best_match.unwrap());

}

#[test]
fn test_enums() {
    assert_eq!("(no error)", format!("{}", rsoundio::SioError::None));
    assert_eq!("ALSA", format!("{}", rsoundio::SioBackend::Alsa));
    assert_eq!("Front Left",
               format!("{}", rsoundio::SioChannelId::FrontLeft));
    assert_eq!(rsoundio::SioChannelId::from("Front Left".to_string()),
               rsoundio::SioChannelId::FrontLeft);
    assert!(rsoundio::SioChannelId::from("SomeInvalidBoredom".to_string()) !=
            rsoundio::SioChannelId::FrontLeft);
    assert_eq!("unsigned 8-bit", format!("{}", rsoundio::SioFormat::U8));
    assert_eq!(1, rsoundio::SioFormat::U8.bytes_per_sample());
    assert_eq!(4, rsoundio::SioFormat::U32LE.bytes_per_sample());
}

#[test]
fn test_device() {
    let sio = rsoundio::SoundIo::new();
    sio.connect().unwrap();
    sio.flush_events();
    let in_dev_idx = sio.default_input_device_index().unwrap();
    let out_dev_idx = sio.default_output_device_index().unwrap();
    let in_dev = sio.input_device(in_dev_idx).unwrap();
    let out_dev = sio.output_device(out_dev_idx).unwrap();
    println!("{}", in_dev);
    println!("{}", out_dev);
    assert!(in_dev != out_dev);
    assert_eq!(in_dev, in_dev);
    out_dev.sort_channel_layouts();
    let stereo_layout = rsoundio::ChannelLayout::default(2).unwrap();
    assert!(in_dev.supports_format(rsoundio::SioFormat::Float32LE));
    assert!(out_dev.supports_format(rsoundio::SioFormat::Float32LE));
    assert!(in_dev.supports_layout(&stereo_layout));
    assert!(out_dev.supports_layout(&stereo_layout));
    assert!(in_dev.supports_sample_rate(48_000));
    assert!(out_dev.supports_sample_rate(48_000));
    assert!(in_dev.nearest_sample_rate(1) > 0);
    assert!(out_dev.nearest_sample_rate(1) > 0);
}
<commit_msg>Fix broken backend assertion<commit_after>extern crate rsoundio;

#[test]
fn test_soundio() {
    let sio = rsoundio::SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.backend(0).is_some());
    sio.connect().unwrap();
    sio.disconnect();
    if sio.have_backend(rsoundio::SioBackend::Alsa) {
        sio.connect_backend(rsoundio::SioBackend::Alsa)
           .unwrap();
        sio.disconnect();
    }
    assert!(rsoundio::SoundIo::channel_layout_builtin_count() >= 0);
    sio.connect().unwrap();
    sio.flush_events();
    assert!(sio.output_device_count().unwrap() > 0);
    assert!(sio.input_device_count().unwrap() > 0);
}

#[test]
fn test_channel_layout() {
    let cnt = rsoundio::SoundIo::channel_layout_builtin_count();
    assert!(cnt > 0);
    assert!(rsoundio::ChannelLayout::builtin(-1).is_none());
    assert_eq!(rsoundio::ChannelLayout::builtin(0),
               rsoundio::ChannelLayout::builtin(0));
    let mut layout = rsoundio::ChannelLayout::default(2).unwrap();
    assert!(layout.detect_builtin());
    assert!(layout.find_channel(rsoundio::SioChannelId::FrontLeft)
                  .is_some());
    assert!(layout.find_channel(rsoundio::SioChannelId::Lfe2)
                  .is_none());
    assert!(cnt > 2);
    let preferred = [rsoundio::ChannelLayout::builtin(0).unwrap(),
                     rsoundio::ChannelLayout::builtin(1).unwrap()];
    let available = [rsoundio::ChannelLayout::builtin(1).unwrap(),
                     rsoundio::ChannelLayout::builtin(2).unwrap()];
    let best_match = rsoundio::ChannelLayout::best_matching_channel_layout(&preferred, &available);
    assert_eq!(rsoundio::ChannelLayout::builtin(1).unwrap(),
               best_match.unwrap());

}

#[test]
fn test_enums() {
    assert_eq!("(no error)", format!("{}", rsoundio::SioError::None));
    assert_eq!("ALSA", format!("{}", rsoundio::SioBackend::Alsa));
    assert_eq!("Front Left",
               format!("{}", rsoundio::SioChannelId::FrontLeft));
    assert_eq!(rsoundio::SioChannelId::from("Front Left".to_string()),
               rsoundio::SioChannelId::FrontLeft);
    assert!(rsoundio::SioChannelId::from("SomeInvalidBoredom".to_string()) !=
            rsoundio::SioChannelId::FrontLeft);
    assert_eq!("unsigned 8-bit", format!("{}", rsoundio::SioFormat::U8));
    assert_eq!(1, rsoundio::SioFormat::U8.bytes_per_sample());
    assert_eq!(4, rsoundio::SioFormat::U32LE.bytes_per_sample());
}

#[test]
fn test_device() {
    let sio = rsoundio::SoundIo::new();
    sio.connect().unwrap();
    sio.flush_events();
    let in_dev_idx = sio.default_input_device_index().unwrap();
    let out_dev_idx = sio.default_output_device_index().unwrap();
    let in_dev = sio.input_device(in_dev_idx).unwrap();
    let out_dev = sio.output_device(out_dev_idx).unwrap();
    println!("{}", in_dev);
    println!("{}", out_dev);
    assert!(in_dev != out_dev);
    assert_eq!(in_dev, in_dev);
    out_dev.sort_channel_layouts();
    let stereo_layout = rsoundio::ChannelLayout::default(2).unwrap();
    assert!(in_dev.supports_format(rsoundio::SioFormat::Float32LE));
    assert!(out_dev.supports_format(rsoundio::SioFormat::Float32LE));
    assert!(in_dev.supports_layout(&stereo_layout));
    assert!(out_dev.supports_layout(&stereo_layout));
    assert!(in_dev.supports_sample_rate(48_000));
    assert!(out_dev.supports_sample_rate(48_000));
    assert!(in_dev.nearest_sample_rate(1) > 0);
    assert!(out_dev.nearest_sample_rate(1) > 0);
}
<|endoftext|>


<commit_before>use neb::ram::cell;
use neb::ram::cell::*;
use neb::ram::schema::*;
use neb::ram::chunk::Chunks;
use neb::ram::types::*;
use neb::ram::io::writer;
use neb::server::ServerMeta;
use env_logger;
use std::sync::atomic::AtomicU8;
use std::sync::atomic::Ordering;
use std;
use std::rc::Rc;

pub const CHUNK_SIZE: usize = 32 * 8 * 1024 * 1024;

#[test]
pub fn round_robin_segment () {
    let num = AtomicU8::new(std::u8::MAX);
    assert_eq!(num.load(Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 0);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 1);
}

#[test]
pub fn cell_rw () {
    let fields = Field {
        type_id: 0,
        name: String::from("*"),
        nullable: false,
        is_array: false,
        sub: Some(vec![
            Field {
                type_id: 6,
                name: String::from("id"),
                nullable:false,
                is_array:false,
                sub: None,
            },
            Field {
                type_id: 20,
                name: String::from("name"),
                nullable:false,
                is_array:false,
                sub: None,
            },
            Field {
                type_id: 10,
                name: String::from("score"),
                nullable:false,
                is_array:false,
                sub: None,
            }
        ])
    };
    let mut schema = Schema::new(String::from("dummy"), None, fields);
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let mut data = Value::Map(data_map);
    let schemas = Schemas::new(None);
    let chunks = Chunks::new(1, CHUNK_SIZE, Rc::<ServerMeta>::new(ServerMeta {
        schemas: schemas.clone()
    }), None);
    schemas.new_schema(&mut schema);
    let mut cell = Cell {
        header: Header::new(0, schema.id, 1, 1),
        data: data
    };
    let mut loc = chunks.write_cell(&mut cell);
    let cell_1_ptr = loc.unwrap();
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(2));
    data_map.insert(String::from("score"), Value::U64(80));
    data_map.insert(String::from("name"), Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, 2, 1),
        data: data
    };
    loc = chunks.write_cell(&mut cell);
    let cell_2_ptr = loc.unwrap();
    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = chunks.read_cell((1, 2)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 2);
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 80);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(2));
    data_map.insert(String::from("score"), Value::U64(95));
    data_map.insert(String::from("name"), Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, 2, 1),
        data: data
    };
    loc = chunks.update_cell(&mut cell);
    let cell_2_ptr = loc.unwrap();
    {
        let stored_cell = chunks.read_cell((1, 2)).unwrap();
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 2);
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 95);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    chunks.remove_cell((1, 1)).unwrap();
    assert!(chunks.read_cell((1, 1)).is_err());
}<commit_msg>some more chunks cell op tests<commit_after>use neb::ram::cell;
use neb::ram::cell::*;
use neb::ram::schema::*;
use neb::ram::chunk::Chunks;
use neb::ram::types::*;
use neb::ram::io::writer;
use neb::server::ServerMeta;
use env_logger;
use std::sync::atomic::AtomicU8;
use std::sync::atomic::Ordering;
use std;
use std::rc::Rc;

pub const CHUNK_SIZE: usize = 32 * 8 * 1024 * 1024;

#[test]
pub fn round_robin_segment () {
    let num = AtomicU8::new(std::u8::MAX);
    assert_eq!(num.load(Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 0);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 1);
}

#[test]
pub fn cell_rw () {
    let fields = Field {
        type_id: 0,
        name: String::from("*"),
        nullable: false,
        is_array: false,
        sub: Some(vec![
            Field {
                type_id: 6,
                name: String::from("id"),
                nullable:false,
                is_array:false,
                sub: None,
            },
            Field {
                type_id: 20,
                name: String::from("name"),
                nullable:false,
                is_array:false,
                sub: None,
            },
            Field {
                type_id: 10,
                name: String::from("score"),
                nullable:false,
                is_array:false,
                sub: None,
            }
        ])
    };
    let mut schema = Schema::new(String::from("dummy"), None, fields);
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let mut data = Value::Map(data_map);
    let schemas = Schemas::new(None);
    let chunks = Chunks::new(1, CHUNK_SIZE, Rc::<ServerMeta>::new(ServerMeta {
        schemas: schemas.clone()
    }), None);
    schemas.new_schema(&mut schema);
    let mut cell = Cell {
        header: Header::new(0, schema.id, 1, 1),
        data: data
    };
    let mut loc = chunks.write_cell(&mut cell);
    let cell_1_ptr = loc.unwrap();
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(2));
    data_map.insert(String::from("score"), Value::U64(80));
    data_map.insert(String::from("name"), Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, 2, 1),
        data: data
    };
    loc = chunks.write_cell(&mut cell);
    let cell_2_ptr = loc.unwrap();
    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = chunks.read_cell((1, 2)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 2);
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 80);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert!(stored_cell.header.size > (4 + HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(2));
    data_map.insert(String::from("score"), Value::U64(95));
    data_map.insert(String::from("name"), Value::String(String::from("John")));
    data = Value::Map(data_map);
    cell = Cell {
        header: Header::new(0, schema.id, 2, 1),
        data: data
    };
    loc = chunks.update_cell(&mut cell);
    let cell_2_ptr = loc.unwrap();
    {
        let stored_cell = chunks.read_cell((1, 2)).unwrap();
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 2);
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 95);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell((1, 1)).unwrap();
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "Jack");
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 70);
    }
    chunks.update_cell_by((1, 2), |mut cell| {
        let mut data_map = Map::<String, Value>::new();
        data_map.insert(String::from("id"), Value::I64(2));
        data_map.insert(String::from("score"), Value::U64(100));
        data_map.insert(String::from("name"), Value::String(String::from("John")));
        let data = Value::Map(data_map);
        cell.data = data;
        Some(cell)
    }).unwrap();
    {
        let stored_cell = chunks.read_cell((1, 2)).unwrap();
        assert_eq!(stored_cell.data.Map().unwrap().get("id").unwrap().I64().unwrap(), 2);
        assert_eq!(stored_cell.data.Map().unwrap().get("score").unwrap().U64().unwrap(), 100);
        assert_eq!(stored_cell.data.Map().unwrap().get("name").unwrap().String().unwrap(), "John");
    }
    chunks.remove_cell((1, 1)).unwrap();
    assert!(chunks.read_cell((1, 1)).is_err());
}<|endoftext|>


<commit_before>//! Attributes & documentation for hir types.

use either::Either;
use hir_def::{
    attr::{AttrsWithOwner, Documentation},
    item_scope::ItemInNs,
    path::ModPath,
    per_ns::PerNs,
    resolver::HasResolver,
    AttrDefId, GenericParamId, ModuleDefId,
};
use hir_expand::{hygiene::Hygiene, MacroDefId};
use hir_ty::db::HirDatabase;
use syntax::ast;

use crate::{
    Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
    MacroDef, Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
};

pub trait HasAttrs {
    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner;
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<Either<ModuleDef, MacroDef>>;
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Namespace {
    Types,
    Values,
    Macros,
}

macro_rules! impl_has_attrs {
    ($(($def:ident, $def_id:ident),)*) => {$(
        impl HasAttrs for $def {
            fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def).docs()
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<Either<ModuleDef, MacroDef>> {
                let def = AttrDefId::$def_id(self.into());
                resolve_doc_path(db, def, link, ns).map(|it| it.map_left(ModuleDef::from).map_right(MacroDef::from))
            }
        }
    )*};
}

impl_has_attrs![
    (Field, FieldId),
    (Variant, EnumVariantId),
    (Static, StaticId),
    (Const, ConstId),
    (Trait, TraitId),
    (TypeAlias, TypeAliasId),
    (MacroDef, MacroDefId),
    (Function, FunctionId),
    (Adt, AdtId),
    (Module, ModuleId),
    (GenericParam, GenericParamId),
    (Impl, ImplId),
];

macro_rules! impl_has_attrs_enum {
    ($($variant:ident),* for $enum:ident) => {$(
        impl HasAttrs for $variant {
            fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                $enum::$variant(self).attrs(db)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                $enum::$variant(self).docs(db)
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<Either<ModuleDef, MacroDef>> {
                $enum::$variant(self).resolve_doc_path(db, link, ns)
            }
        }
    )*};
}

impl_has_attrs_enum![Struct, Union, Enum for Adt];
impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];

impl HasAttrs for AssocItem {
    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
        match self {
            AssocItem::Function(it) => it.attrs(db),
            AssocItem::Const(it) => it.attrs(db),
            AssocItem::TypeAlias(it) => it.attrs(db),
        }
    }

    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
        match self {
            AssocItem::Function(it) => it.docs(db),
            AssocItem::Const(it) => it.docs(db),
            AssocItem::TypeAlias(it) => it.docs(db),
        }
    }

    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<Either<ModuleDef, MacroDef>> {
        match self {
            AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
            AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
            AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
        }
    }
}

fn resolve_doc_path(
    db: &dyn HirDatabase,
    def: AttrDefId,
    link: &str,
    ns: Option<Namespace>,
) -> Option<Either<ModuleDefId, MacroDefId>> {
    let resolver = match def {
        AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
        AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::AdtId(it) => it.resolver(db.upcast()),
        AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
        AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::StaticId(it) => it.resolver(db.upcast()),
        AttrDefId::ConstId(it) => it.resolver(db.upcast()),
        AttrDefId::TraitId(it) => it.resolver(db.upcast()),
        AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
        AttrDefId::ImplId(it) => it.resolver(db.upcast()),
        AttrDefId::GenericParamId(it) => match it {
            GenericParamId::TypeParamId(it) => it.parent,
            GenericParamId::LifetimeParamId(it) => it.parent,
            GenericParamId::ConstParamId(it) => it.parent,
        }
        .resolver(db.upcast()),
        // FIXME
        AttrDefId::MacroDefId(_) => return None,
    };
    let path = ast::Path::parse(link).ok()?;
    let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic()).unwrap();
    let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
    let resolved = if resolved == PerNs::none() {
        resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
    } else {
        resolved
    };
    match ns {
        Some(Namespace::Types) => resolved.take_types().map(Either::Left),
        Some(Namespace::Values) => resolved.take_values().map(Either::Left),
        Some(Namespace::Macros) => resolved.take_macros().map(Either::Right),
        None => resolved.iter_items().next().map(|it| match it {
            ItemInNs::Types(it) => Either::Left(it),
            ItemInNs::Values(it) => Either::Left(it),
            ItemInNs::Macros(it) => Either::Right(it),
        }),
    }
}
<commit_msg>Remove unwrap in doc path resolution<commit_after>//! Attributes & documentation for hir types.

use either::Either;
use hir_def::{
    attr::{AttrsWithOwner, Documentation},
    item_scope::ItemInNs,
    path::ModPath,
    per_ns::PerNs,
    resolver::HasResolver,
    AttrDefId, GenericParamId, ModuleDefId,
};
use hir_expand::{hygiene::Hygiene, MacroDefId};
use hir_ty::db::HirDatabase;
use syntax::ast;

use crate::{
    Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
    MacroDef, Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
};

pub trait HasAttrs {
    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner;
    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<Either<ModuleDef, MacroDef>>;
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Namespace {
    Types,
    Values,
    Macros,
}

macro_rules! impl_has_attrs {
    ($(($def:ident, $def_id:ident),)*) => {$(
        impl HasAttrs for $def {
            fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                let def = AttrDefId::$def_id(self.into());
                db.attrs(def).docs()
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<Either<ModuleDef, MacroDef>> {
                let def = AttrDefId::$def_id(self.into());
                resolve_doc_path(db, def, link, ns).map(|it| it.map_left(ModuleDef::from).map_right(MacroDef::from))
            }
        }
    )*};
}

impl_has_attrs![
    (Field, FieldId),
    (Variant, EnumVariantId),
    (Static, StaticId),
    (Const, ConstId),
    (Trait, TraitId),
    (TypeAlias, TypeAliasId),
    (MacroDef, MacroDefId),
    (Function, FunctionId),
    (Adt, AdtId),
    (Module, ModuleId),
    (GenericParam, GenericParamId),
    (Impl, ImplId),
];

macro_rules! impl_has_attrs_enum {
    ($($variant:ident),* for $enum:ident) => {$(
        impl HasAttrs for $variant {
            fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                $enum::$variant(self).attrs(db)
            }
            fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
                $enum::$variant(self).docs(db)
            }
            fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<Either<ModuleDef, MacroDef>> {
                $enum::$variant(self).resolve_doc_path(db, link, ns)
            }
        }
    )*};
}

impl_has_attrs_enum![Struct, Union, Enum for Adt];
impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];

impl HasAttrs for AssocItem {
    fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
        match self {
            AssocItem::Function(it) => it.attrs(db),
            AssocItem::Const(it) => it.attrs(db),
            AssocItem::TypeAlias(it) => it.attrs(db),
        }
    }

    fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
        match self {
            AssocItem::Function(it) => it.docs(db),
            AssocItem::Const(it) => it.docs(db),
            AssocItem::TypeAlias(it) => it.docs(db),
        }
    }

    fn resolve_doc_path(
        self,
        db: &dyn HirDatabase,
        link: &str,
        ns: Option<Namespace>,
    ) -> Option<Either<ModuleDef, MacroDef>> {
        match self {
            AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
            AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
            AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
        }
    }
}

fn resolve_doc_path(
    db: &dyn HirDatabase,
    def: AttrDefId,
    link: &str,
    ns: Option<Namespace>,
) -> Option<Either<ModuleDefId, MacroDefId>> {
    let resolver = match def {
        AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
        AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::AdtId(it) => it.resolver(db.upcast()),
        AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
        AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
        AttrDefId::StaticId(it) => it.resolver(db.upcast()),
        AttrDefId::ConstId(it) => it.resolver(db.upcast()),
        AttrDefId::TraitId(it) => it.resolver(db.upcast()),
        AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
        AttrDefId::ImplId(it) => it.resolver(db.upcast()),
        AttrDefId::GenericParamId(it) => match it {
            GenericParamId::TypeParamId(it) => it.parent,
            GenericParamId::LifetimeParamId(it) => it.parent,
            GenericParamId::ConstParamId(it) => it.parent,
        }
        .resolver(db.upcast()),
        // FIXME
        AttrDefId::MacroDefId(_) => return None,
    };
    let path = ast::Path::parse(link).ok()?;
    let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic())?;
    let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
    let resolved = if resolved == PerNs::none() {
        resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
    } else {
        resolved
    };
    match ns {
        Some(Namespace::Types) => resolved.take_types().map(Either::Left),
        Some(Namespace::Values) => resolved.take_values().map(Either::Left),
        Some(Namespace::Macros) => resolved.take_macros().map(Either::Right),
        None => resolved.iter_items().next().map(|it| match it {
            ItemInNs::Types(it) => Either::Left(it),
            ItemInNs::Values(it) => Either::Left(it),
            ItemInNs::Macros(it) => Either::Right(it),
        }),
    }
}
<|endoftext|>


<commit_before><commit_msg>handle all the reads on the "main" watcher thread<commit_after><|endoftext|>