<commit_before>#![feature(unboxed_closures, macro_rules, globs)]

extern crate shader_version;
extern crate event;
extern crate event_loop;
extern crate conrod;
extern crate graphics;
extern crate window;
extern crate opengl_graphics;
extern crate current;

use conrod::*;

use current::Set;

use event::Event;
use event_loop::{Events, Ups, MaxFps};

use opengl_graphics::Gl;
use opengl_graphics::glyph_cache::GlyphCache as Font;

use shader_version::opengl::OpenGL;

use window::{Window, WindowSettings};

use std::comm::TryRecvError;

use std::default::Default;

use std::io::fs::{mod, PathExtensions};
use std::io::IoResult;

use std::os;

use std::cell::Cell;

pub struct FileDialog {
    title: String,
    dimen: [u32, ..2],
    samples: u8,
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    filter_hidden: bool,
}

macro_rules! setter(
    ($field:ident: $ty:ty -> $ret:ident) => (
        fn $field(mut self, $field: $ty) -> $ret {
            self.$field = $field;
            self
        }
    );
)

impl FileDialog {
    pub fn new<S: StrAllocating>(title: S, font: Font) -> FileDialog {
        FileDialog {
            title: title.into_string(),
            dimen: [640, 480],
            samples: 4,
            background: Color::new(0.9, 0.9, 0.9, 1.0), // Should be a nice light-grey
            select: SelectType::File,
            // Possible panic! here, but unlikely.
            starting_path: os::homedir().unwrap_or_else(|| os::getcwd().unwrap()),
            font: font,
            filter_hidden: true,
        }
    }

    pub fn width(mut self, width: u32) -> FileDialog {
        self.dimen[0] = width;
        self
    }

    pub fn height(mut self, height: u32) -> FileDialog {
        self.dimen[1] = height;
        self
    }

    pub fn dimensions(mut self, width: u32, height: u32) -> FileDialog {
        self.dimen = [width, height];
        self
    }

    setter!(samples: u8 -> FileDialog)

    setter!(background: Color -> FileDialog)

    setter!(select: SelectType -> FileDialog)

    setter!(starting_path: Path -> FileDialog)

    setter!(filter_hidden: bool -> FileDialog)

    // How should we format the trait bounds here?
    /// Show the dialog
    pub fn show<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W + Send>
    (self, win_fn: F, gl: OpenGL) -> FilePromise {
        let (promise, tx) = FilePromise::new();
        let (dialog, window) = self.explode(tx);

        spawn(proc() render_file_dialog(dialog, window, gl, win_fn));

        promise
    }

    fn explode(self, tx: Sender<Path>) -> (DialogSettings, WindowSettings) {
        (
            DialogSettings {
                background: self.background,
                select: self.select,
                starting_path: self.starting_path,
                font: self.font,
                tx: tx,
                filter_hidden: self.filter_hidden,
            },
            WindowSettings {
                title: self.title,
                size: self.dimen,
                samples: self.samples,
                fullscreen: false,
                exit_on_esc: true,
            }
        )
    }
}

/// An enum describing the file selection behavior.
pub enum SelectType {
    /// User must select an existing file on the filesystem.
    File,
    /// User must select an existing folder on the filesystem, or create a new one.
    Folder,
    /// User must select the location to save a file, and the filename.
    /// The contained `Option<String>` is the default filename, if any.
    SaveFile(Option<String>),
}

impl SelectType {
    fn show_files(&self) -> bool {
        match *self {
            SelectType::File | SelectType::SaveFile(_) => true,
            _ => false,
        }
    }
}

struct DialogSettings {
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    tx: Sender<Path>,
    filter_hidden: bool,
}

impl DialogSettings {
    fn into_state(self) -> (DialogState, Font) {
        (
            DialogState {
                dir: self.starting_path,
                selected: None,
                paths: Vec::new(),
                background: self.background,
                select: self.select,
                dir_changed: false,
                pages: 0,
                cur_page: 0,
                tx: self.tx,
                exit: false,
                filter_hidden: self.filter_hidden,
            },
            self.font,
        )
    }
}

fn render_file_dialog<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W>
(dialog: DialogSettings, window: WindowSettings, gl: OpenGL, win_fn: F) {
    let (mut state, font) = dialog.into_state();
    state.update_paths();

    let ref mut state = state;

    let window = win_fn(gl, window);
    let mut event_loop = Events::new(window).set(Ups(120)).set(MaxFps(60));
    let mut gl = Gl::new(gl);

    let ref mut uic = UiContext::new(font, Theme::default());
    let ref mut buf = Default::default();

    for event in event_loop {
        if state.exit { break; }

        uic.handle_event(&event);
        match event {
            Event::Render(args) => {
                gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                    draw_dialog_ui(gl, uic, state, buf);
                });
            },
            _ => {}
        }
    }
}

#[deriving(Default)]
struct Buffers {
    dir: String,
    page: String,
}

impl Buffers {
    fn set_page(&mut self, page: uint, total: uint) {
        self.page = format!("Page: {} Total: {}", page, total);
    }
}

struct DialogState {
    dir: Path,
    selected: Option<uint>,
    paths: Vec<Path>,
    background: Color,
    select: SelectType,
    dir_changed: bool,
    pages: uint,
    cur_page: uint,
    tx: Sender<Path>,
    exit: bool,
    filter_hidden: bool,
}

impl DialogState {
    fn update_dir(&mut self, new_dir: Path) {
        self.dir_changed = if new_dir.is_dir() {
            self.dir = new_dir;
            self.update_paths();
            true
        } else {
            false
        }
    }

    fn update_paths(&mut self) {
        self.selected = None;
        self.paths = entries(&self.dir, self.select.show_files(), self.filter_hidden).unwrap();

        let count = self.paths.len();
        self.pages = count / PER_PAGE;
        self.cur_page = 1;

        if count % PER_PAGE != 0 { self.pages += 1; }
    }

    fn up_dir(&mut self) {
        self.dir_changed = self.dir.pop();
        self.update_paths();
    }

    fn select(&mut self, num: uint) {
        // Double-clicked
        if self.selected == Some(num) {
            let path = self.paths.remove(num).unwrap();

            if self.select.show_files() && !path.is_dir() {
                self.tx.send(path);
                self.exit = true;
            } else {
                self.update_dir(path);
            }
        } else {
            self.selected = Some(num);
        }
    }
}

const COLS: uint = 5;
const ROWS: uint = 8;
const PER_PAGE: uint = COLS * ROWS;
const CHAR_LIMIT: uint = 24;

fn draw_dialog_ui(gl: &mut Gl, uic: &mut UiContext, state: &mut DialogState, buf: &mut Buffers) {
    uic.background().color(state.background).draw(gl);

    CUR_PAGE.with(|cur_page| {
        let page = cur_page.get();
        if page != state.cur_page {
            state.cur_page = page;
            buf.set_page(state.cur_page, state.pages);
        }
    });

    if state.dir_changed {
        buf.dir.clear();
        buf.set_page(state.cur_page, state.pages);
        state.dir_changed = false;
    }

    if buf.dir.is_empty() {
        state.dir.as_str().map(|s| buf.dir.push_str(s));
        buf.set_page(state.cur_page, state.pages);
    }

    thread_local!(static CUR_PAGE: Cell<uint> = Cell::new(1))

    const BUTTON_ID: u64 = 78;

    uic.button(BUTTON_ID)
        .position(605.0, 5.0)
        .dimensions(30.0, 30.0)
        .label("Up")
        .callback(|| state.up_dir())
        .draw(gl);

    uic.label(&*buf.dir)
        .position(5.0, 5.0)
        .size(24)
        .draw(gl);

    const PREV_PAGE: u64 = 199;

    uic.button(PREV_PAGE)
        .position(5.0, 445.0)
        .dimensions(90.0, 30.0)
        .label("Previous")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page > 1 { cur_page.set(page - 1); }
        }))
        .draw(gl);

    uic.button(PREV_PAGE + 1)
        .right_from(PREV_PAGE, 125.0)
        .dimensions(90.0, 30.0)
        .label("Next")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page < state.pages { cur_page.set(page + 1); }
        }))
        .draw(gl);

    uic.label(&*buf.page)
        .right_from(PREV_PAGE, 15.0)
        .size(24)
        .draw(gl);

    const FILE_START_ID: u64 = 365;
    uic.widget_matrix(COLS, ROWS)
        .position(5.0, 35.0)
        .dimensions(600.0, 400.0)
        .cell_padding(5.0, 5.0)
        .each_widget(|uic, _, x, y, pt, dimen| {
            use std::cmp;
            let idx = y * COLS + x;

            if idx >= state.paths.len() { return; }

            let label = state.paths[idx].filename_str().unwrap().into_string();

            let button = uic.button(FILE_START_ID + idx as u64)
                .point(pt)
                .dimensions(dimen[0], dimen[1])
                .label(label.slice_to(cmp::min(label.len(), CHAR_LIMIT))).label_font_size(18);

                if state.selected == Some(idx) {
                    button.color(Color::new(0.5, 0.9, 0.5, 1.0))
                } else { button }
                .callback(|| state.select(idx))
                .draw(gl);
        });
}

fn entries(path: &Path, keep_files: bool, filter_hidden: bool) -> IoResult<Vec<Path>> {
    let mut entries = try!(fs::readdir(path));
    entries.retain(|file|
        (filter_hidden && !file.filename_str().unwrap().starts_with(".")) &&
        (keep_files || file.is_dir())
    );
    entries.sort();

    Ok(entries)
}

pub struct FilePromise {
    opt: Option<Path>,
    rx: Receiver<Path>,
}

impl FilePromise {
    pub fn new() -> (FilePromise, Sender<Path>) {
        let (tx, rx) = channel();

        (
            FilePromise {
                opt: None,
                rx: rx,
            },
            tx,
        )
    }

    pub fn poll(&mut self) -> Option<&Path> {
        match self.rx.try_recv() {
            Ok(val) => self.opt = Some(val),
            Err(TryRecvError::Empty) => return None,
            Err(TryRecvError::Disconnected) if self.opt.is_none() =>
                panic!("Promised value never received; processing task ended prematurely!"),
            _ => (),
        }

        self.opt.as_ref()
    }

    pub fn unwrap(mut self) -> Path {
        while self.poll().is_none() {}

        self.opt.unwrap()
    }
}
<commit_msg>Implement file saving<commit_after>#![feature(unboxed_closures, macro_rules, globs)]

extern crate shader_version;
extern crate event;
extern crate event_loop;
extern crate conrod;
extern crate graphics;
extern crate window;
extern crate opengl_graphics;
extern crate current;

use conrod::*;

use current::Set;

use event::Event;
use event_loop::{Events, Ups, MaxFps};

use opengl_graphics::Gl;
use opengl_graphics::glyph_cache::GlyphCache as Font;

use shader_version::opengl::OpenGL;

use window::{Window, WindowSettings};

use std::comm::TryRecvError;

use std::default::Default;

use std::io::fs::{mod, PathExtensions};
use std::io::IoResult;

use std::os;

use std::cell::Cell;

pub struct FileDialog {
    title: String,
    dimen: [u32, ..2],
    samples: u8,
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    filter_hidden: bool,
}

macro_rules! setter(
    (pub $fn_nm: ident, $field:ident: $ty:ty -> $ret:ident) => (
        pub fn $fn_nm(mut self, $field: $ty) -> $ret {
            self.$field = $field;
            self
        }
    );
)

impl FileDialog {
    pub fn new<S: StrAllocating>(title: S, font: Font) -> FileDialog {
        FileDialog {
            title: title.into_string(),
            dimen: [640, 480],
            samples: 4,
            background: Color::new(0.9, 0.9, 0.9, 1.0), // Should be a nice light-grey
            select: SelectType::File,
            // Possible panic! here, but unlikely.
            starting_path: os::homedir().unwrap_or_else(|| os::getcwd().unwrap()),
            font: font,
            filter_hidden: true,
        }
    }

    pub fn width(mut self, width: u32) -> FileDialog {
        self.dimen[0] = width;
        self
    }

    pub fn height(mut self, height: u32) -> FileDialog {
        self.dimen[1] = height;
        self
    }

    pub fn dimensions(mut self, width: u32, height: u32) -> FileDialog {
        self.dimen = [width, height];
        self
    }

    pub fn set_samples(mut self, samples: u8) -> FileDialog {
        self.samples = samples;
        self
    }

    pub fn set_background(mut self, background: Color) -> FileDialog {
        self.background = background;
        self
    }

    pub fn set_select(mut self, select: SelectType) -> FileDialog {
        self.select = select;
        self
    }

    pub fn set_starting_path(mut self, starting_path: Path) -> FileDialog {
        self.starting_path = starting_path;
        self
    }

    pub fn set_filter_hidden(mut self, filter_hidden: bool) -> FileDialog {
        self.filter_hidden = filter_hidden;
        self
    }

    // How should we format the trait bounds here?
    /// Show the dialog
    pub fn show<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W + Send>
    (self, win_fn: F, gl: OpenGL) -> FilePromise {
        let (promise, tx) = FilePromise::new();
        let (dialog, window) = self.explode(tx);

        spawn(proc() render_file_dialog(dialog, window, gl, win_fn));

        promise
    }

    fn explode(self, tx: Sender<Path>) -> (DialogSettings, WindowSettings) {
        (
            DialogSettings {
                background: self.background,
                select: self.select,
                starting_path: self.starting_path,
                font: self.font,
                tx: tx,
                filter_hidden: self.filter_hidden,
            },
            WindowSettings {
                title: self.title,
                size: self.dimen,
                samples: self.samples,
                fullscreen: false,
                exit_on_esc: true,
            }
        )
    }
}

/// An enum describing the file selection behavior.
#[deriving(PartialEq, Eq)]
pub enum SelectType {
    /// User must select an existing file on the filesystem.
    File,
    /// User must select an existing folder on the filesystem, or create a new one.
    Folder,
    /// User must select the location to save a file, and the filename.
    /// The contained `Option<String>` is the default filename, if any.
    SaveFile(Option<String>),
}

impl SelectType {
    fn show_files(&self) -> bool {
        match *self {
            SelectType::File | SelectType::SaveFile(_) => true,
            _ => false,
        }
    }
}

struct DialogSettings {
    background: Color,
    select: SelectType,
    starting_path: Path,
    font: Font,
    tx: Sender<Path>,
    filter_hidden: bool,
}

impl DialogSettings {
    fn into_state(self) -> (DialogState, Font) {
        (
            DialogState {
                dir: self.starting_path,
                selected: None,
                paths: Vec::new(),
                background: self.background,
                select: self.select,
                dir_changed: false,
                pages: 0,
                cur_page: 0,
                tx: self.tx,
                exit: false,
                filter_hidden: self.filter_hidden,
            },
            self.font,
        )
    }
}

fn render_file_dialog<W: Window, F: FnOnce(OpenGL, WindowSettings) -> W>
(dialog: DialogSettings, window: WindowSettings, gl: OpenGL, win_fn: F) {
    let (mut state, font) = dialog.into_state();
    state.update_paths();

    let ref mut state = state;

    let window = win_fn(gl, window);
    let mut event_loop = Events::new(window).set(Ups(120)).set(MaxFps(60));
    let mut gl = Gl::new(gl);

    let ref mut uic = UiContext::new(font, Theme::default());
    let ref mut buf: Buffers = Default::default();

    if let SelectType::SaveFile(ref mut opt_file) = state.select {
        opt_file.take().map(|s: String| buf.filename = s);
    }

    for event in event_loop {
        if state.exit { break; }

        uic.handle_event(&event);
        match event {
            Event::Render(args) => {
                gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                    draw_dialog_ui(gl, uic, state, buf);
                });
            },
            _ => {}
        }
    }
}

#[deriving(Default)]
struct Buffers {
    dir: String,
    page: String,
    filename: String,
}

impl Buffers {
    fn set_page(&mut self, page: uint, total: uint) {
        self.page = format!("Page: {} Total: {}", page, total);
    }
}

struct DialogState {
    dir: Path,
    selected: Option<uint>,
    paths: Vec<Path>,
    background: Color,
    select: SelectType,
    dir_changed: bool,
    pages: uint,
    cur_page: uint,
    tx: Sender<Path>,
    exit: bool,
    filter_hidden: bool,
}

impl DialogState {
    fn update_dir(&mut self, new_dir: Path) {
        self.dir_changed = if new_dir.is_dir() {
            self.dir = new_dir;
            self.update_paths();
            true
        } else {
            false
        }
    }

    fn update_paths(&mut self) {
        self.selected = None;
        self.paths = entries(&self.dir, self.select.show_files(), self.filter_hidden).unwrap();

        let count = self.paths.len();
        self.pages = count / PER_PAGE;
        self.cur_page = 1;

        if count % PER_PAGE != 0 { self.pages += 1; }
    }

    fn up_dir(&mut self) {
        self.dir_changed = self.dir.pop();
        self.update_paths();
    }

    fn select(&mut self, num: uint) {
        // Double-clicked
        if self.selected == Some(num) {
            let path = self.paths.remove(num).unwrap();

            if self.select.show_files() && !path.is_dir() {
                self.tx.send(path);
                self.exit = true;
            } else {
                self.update_dir(path);
            }
        } else {
            self.selected = Some(num);
        }
    }

    fn save(&mut self, filename: &str) {
        self.tx.send(self.dir.join(filename));
        self.exit = true;
    }
}

const COLS: uint = 5;
const ROWS: uint = 8;
const PER_PAGE: uint = COLS * ROWS;
const CHAR_LIMIT: uint = 24;

fn draw_dialog_ui(gl: &mut Gl, uic: &mut UiContext, state: &mut DialogState, buf: &mut Buffers) {
    uic.background().color(state.background).draw(gl);

    CUR_PAGE.with(|cur_page| {
        let page = cur_page.get();
        if page != state.cur_page {
            state.cur_page = page;
            buf.set_page(state.cur_page, state.pages);
        }
    });

    if state.dir_changed {
        buf.dir.clear();
        buf.set_page(state.cur_page, state.pages);
        state.dir_changed = false;
    }

    if buf.dir.is_empty() {
        state.dir.as_str().map(|s| buf.dir.push_str(s));
        buf.set_page(state.cur_page, state.pages);
    }

    thread_local!(static CUR_PAGE: Cell<uint> = Cell::new(1))

    const UP_DIR: u64 = 78;

    uic.button(UP_DIR)
        .position(605.0, 5.0)
        .dimensions(30.0, 30.0)
        .label("Up")
        .callback(|| state.up_dir())
        .draw(gl);

    uic.label(&*buf.dir)
        .position(5.0, 5.0)
        .size(24)
        .draw(gl);

    const PREV_PAGE: u64 = 199;

    uic.button(PREV_PAGE)
        .position(5.0, 445.0)
        .dimensions(90.0, 30.0)
        .label("Previous")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page > 1 { cur_page.set(page - 1); }
        }))
        .draw(gl);

    const NEXT_PAGE: u64 = PREV_PAGE + 1;

    uic.button(NEXT_PAGE)
        .right_from(PREV_PAGE, 125.0)
        .dimensions(90.0, 30.0)
        .label("Next")
        .callback(|| CUR_PAGE.with(|cur_page| {
            let page = cur_page.get();
            if page < state.pages { cur_page.set(page + 1); }
        }))
        .draw(gl);

    uic.label(&*buf.page)
        .right_from(PREV_PAGE, 15.0)
        .size(24)
        .draw(gl);

    const FILE_START_ID: u64 = 365;
    uic.widget_matrix(COLS, ROWS)
        .position(5.0, 35.0)
        .dimensions(600.0, 400.0)
        .cell_padding(5.0, 5.0)
        .each_widget(|uic, _, x, y, pt, dimen| {
            use std::cmp;
            let idx = y * COLS + x;

            if idx >= state.paths.len() { return; }

            let label = state.paths[idx].filename_str().unwrap().into_string();

            let button = uic.button(FILE_START_ID + idx as u64)
                .point(pt)
                .dimensions(dimen[0], dimen[1])
                .label(label.slice_to(cmp::min(label.len(), CHAR_LIMIT))).label_font_size(18);

                if state.selected == Some(idx) {
                    button.color(Color::new(0.5, 0.9, 0.5, 1.0))
                } else { button }
                .callback(|| state.select(idx))
                .draw(gl);
        });

    const CANCEL: u64 = 205;
    const CONFIRM: u64 = 206;

    uic.button(CANCEL)
        .right_from(NEXT_PAGE, 150.0)
        .dimensions(90.0, 30.0)
        .callback(|| state.exit = true)
        .label("Cancel")
        .draw(gl);

    {
        let confirm = uic.button(CONFIRM)
            .right_from(CANCEL, 5.0)
            .dimensions(90.0, 30.0);

        if let Some(idx) = state.selected {
            confirm.label(match state.select {
                    SelectType::SaveFile(_) if !state.paths[idx].is_dir() => "Save",
                    _ => "Open",
                })
                .callback(|| state.select(idx))
                .draw(gl);
        } else if state.select == SelectType::Folder {
            confirm.label("Select Folder")
                .callback(|| {
                    state.tx.send(state.dir.clone());
                    state.exit = true
                })
                .draw(gl);
        } else if let SelectType::SaveFile(_) = state.select {
            let confirm = confirm.label("Save");

            if !buf.filename.is_empty() {
                confirm.callback(|| state.save(&*buf.filename))
            } else {
                confirm
            }.draw(gl);
        } else {
            confirm.label("Open").draw(gl);
        }
    }

    const FILENAME: u64 = 210;
    if let SelectType::SaveFile(_) = state.select {
        uic.text_box(FILENAME, &mut buf.filename)
            .right_from(NEXT_PAGE, 5.0)
            .dimensions(140.0, 30.0)
            .draw(gl);
    }
}

fn entries(path: &Path, keep_files: bool, filter_hidden: bool) -> IoResult<Vec<Path>> {
    let mut entries = try!(fs::readdir(path));
    entries.retain(|file|
        (filter_hidden && !file.filename_str().unwrap().starts_with(".")) &&
        (keep_files || file.is_dir())
    );
    entries.sort();

    Ok(entries)
}

pub struct FilePromise {
    opt: Option<Path>,
    rx: Receiver<Path>,
}

impl FilePromise {
    pub fn new() -> (FilePromise, Sender<Path>) {
        let (tx, rx) = channel();

        (
            FilePromise {
                opt: None,
                rx: rx,
            },
            tx,
        )
    }

    pub fn poll(&mut self) -> Option<&Path> {
        match self.rx.try_recv() {
            Ok(val) => self.opt = Some(val),
            Err(TryRecvError::Empty) => return None,
            Err(TryRecvError::Disconnected) if self.opt.is_none() =>
                panic!("Promised value never received; processing task ended prematurely!"),
            _ => (),
        }

        self.opt.as_ref()
    }

    pub fn unwrap(mut self) -> Path {
        while self.poll().is_none() {}

        self.opt.unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lock-free queues.

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

use std::error;
use std::fmt;

//================================================
// Enums
//================================================

// ConsumeError __________________________________

/// Indicates the reason a `consume` operation could not return an item.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ConsumeError {
    /// The queue was empty and had no remaining producers.
    Disconnected,
    /// The queue was empty.
    Empty,
}

impl error::Error for ConsumeError {
    fn description(&self) -> &str {
        match *self {
            ConsumeError::Disconnected => "the queue was empty and had no remaining producers",
            ConsumeError::Empty => "the queue was empty",
        }
    }
}

impl fmt::Display for ConsumeError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", error::Error::description(self))
    }
}
<commit_msg>Add ProduceError enum<commit_after>// Copyright 2017 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lock-free queues.

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

use std::error;
use std::fmt;

//================================================
// Enums
//================================================

// ConsumeError __________________________________

/// Indicates the reason a `consume` operation could not return an item.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ConsumeError {
    /// The queue was empty and had no remaining producers.
    Disconnected,
    /// The queue was empty.
    Empty,
}

impl error::Error for ConsumeError {
    fn description(&self) -> &str {
        match *self {
            ConsumeError::Disconnected => "the queue was empty and had no remaining producers",
            ConsumeError::Empty => "the queue was empty",
        }
    }
}

impl fmt::Display for ConsumeError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", error::Error::description(self))
    }
}

// ProduceError __________________________________

/// Indicates the reason a `produce` operation rejected an item.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ProduceError<T> {
    /// The queue had no remaining consumers.
    Disconnected(T),
    /// The queue was full.
    Full(T),
}

impl<T> ProduceError<T> {
    //- Consumers --------------------------------

    /// Returns the rejected item.
    pub fn item(self) -> T {
        match self { ProduceError::Disconnected(item) | ProduceError::Full(item) => item }
    }
}

impl<T> error::Error for ProduceError<T> {
    fn description(&self) -> &str {
        match *self {
            ProduceError::Disconnected(_) => "the queue had no remaining consumers",
            ProduceError::Full(_) => "the queue was full",
        }
    }
}

impl<T> fmt::Debug for ProduceError<T> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ProduceError::Disconnected(_) => write!(formatter, "ProduceError::Disconnected(..)"),
            ProduceError::Full(_) => write!(formatter, "ProduceError::Full(..)"),
        }
    }
}

impl<T> fmt::Display for ProduceError<T> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

extern crate cairo_sys as ffi;
extern crate libc;
extern crate glib;
extern crate c_vec;

pub use ffi::enums;
pub use ffi::cairo_rectangle_t as Rectangle;
pub use ffi::cairo_rectangle_int_t as RectangleInt;

pub use context::{
    Context,
    RectangleVec,
};

pub use paths::{
    Path,
    PathSegments,
    PathSegment
};

pub use enums::{
    Status,
    Antialias,
    FillRule,
    LineCap,
    LineJoin,
    Operator,
    PathDataType,
    Format,
    SurfaceType,
};

pub use patterns::{
    //Traits
    Pattern,
    Gradient,

    //Structs
    LinearGradient,
    RadialGradient,
    SolidPattern,
    SurfacePattern,
};

#[cfg(feature = "1.12")]
pub use patterns::{
    Mesh,
    MeshCorner,
};

pub use fonts::{
    FontFace,
    ScaledFont,
    FontOptions,

    Glyph,
    FontExtents,
    TextExtents,
    TextCluster,
};

pub use matrices::{
    Matrix,
    MatrixTrait,
};

pub use image_surface::ImageSurface;
pub use surface::Surface;

pub mod prelude;

mod fonts;
mod context;
mod error;
mod image_surface;
#[cfg(feature = "png")]
mod image_surface_png;
mod paths;
mod patterns;
mod surface;
mod matrices;
<commit_msg>Reexport IoError<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

extern crate cairo_sys as ffi;
extern crate libc;
extern crate glib;
extern crate c_vec;

pub use ffi::enums;
pub use ffi::cairo_rectangle_t as Rectangle;
pub use ffi::cairo_rectangle_int_t as RectangleInt;

pub use context::{
    Context,
    RectangleVec,
};

pub use paths::{
    Path,
    PathSegments,
    PathSegment
};

pub use enums::{
    Status,
    Antialias,
    FillRule,
    LineCap,
    LineJoin,
    Operator,
    PathDataType,
    Format,
    SurfaceType,
};

pub use error::IoError;

pub use patterns::{
    //Traits
    Pattern,
    Gradient,

    //Structs
    LinearGradient,
    RadialGradient,
    SolidPattern,
    SurfacePattern,
};

#[cfg(feature = "1.12")]
pub use patterns::{
    Mesh,
    MeshCorner,
};

pub use fonts::{
    FontFace,
    ScaledFont,
    FontOptions,

    Glyph,
    FontExtents,
    TextExtents,
    TextCluster,
};

pub use matrices::{
    Matrix,
    MatrixTrait,
};

pub use image_surface::ImageSurface;
pub use surface::Surface;

pub mod prelude;

mod fonts;
mod context;
mod error;
mod image_surface;
#[cfg(feature = "png")]
mod image_surface_png;
mod paths;
mod patterns;
mod surface;
mod matrices;
<|endoftext|>


<commit_before>#![no_std]
#![cfg(feature = "serde")]

#[macro_use]
extern crate enum_map;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate serde_test;

use enum_map::EnumMap;

use serde_test::{assert_tokens, Token};

#[derive(Debug, EnumMap, Deserialize, Serialize)]
enum Example {
    A,
    B,
}

#[test]
fn serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(2) },
            Token::UnitVariant {
                name: "Example",
                variant: "A",
            },
            Token::I32(5),
            Token::UnitVariant {
                name: "Example",
                variant: "B",
            },
            Token::I32(10),
            Token::MapEnd,
        ],
    );
}

const JSON: &str = r#"{"A":5,"B":10}"#;

#[test]
fn json_serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_eq!(serde_json::to_string(&map).unwrap(), String::from(JSON));
}

#[test]
fn json_deserialization() {
    let example: EnumMap<Example, i32> = serde_json::from_str(JSON).unwrap();
    assert_eq!(example, enum_map! { Example::A => 5, Example::B => 10 });
}

#[test]
fn json_invalid_deserialization() {
    let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str(r"{}");
    assert!(example.is_err());
}

#[test]
fn json_invalid_key() {
    let example: Result<EnumMap<Example, i32>, _> =
        serde_json::from_str(r#"{"a": 5, "b": 10, "c": 6}"#);
    assert!(example.is_err());
}
<commit_msg>Remove no_std from Serde tests<commit_after>#![cfg(feature = "serde")]

#[macro_use]
extern crate enum_map;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate serde_test;

use enum_map::EnumMap;

use serde_test::{assert_tokens, Token};

#[derive(Debug, EnumMap, Deserialize, Serialize)]
enum Example {
    A,
    B,
}

#[test]
fn serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(2) },
            Token::UnitVariant {
                name: "Example",
                variant: "A",
            },
            Token::I32(5),
            Token::UnitVariant {
                name: "Example",
                variant: "B",
            },
            Token::I32(10),
            Token::MapEnd,
        ],
    );
}

const JSON: &str = r#"{"A":5,"B":10}"#;

#[test]
fn json_serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_eq!(serde_json::to_string(&map).unwrap(), String::from(JSON));
}

#[test]
fn json_deserialization() {
    let example: EnumMap<Example, i32> = serde_json::from_str(JSON).unwrap();
    assert_eq!(example, enum_map! { Example::A => 5, Example::B => 10 });
}

#[test]
fn json_invalid_deserialization() {
    let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str(r"{}");
    assert!(example.is_err());
}

#[test]
fn json_invalid_key() {
    let example: Result<EnumMap<Example, i32>, _> =
        serde_json::from_str(r#"{"a": 5, "b": 10, "c": 6}"#);
    assert!(example.is_err());
}
<|endoftext|>


<commit_before>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "doc", feature(external_doc))]
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-beta.1")]
#![cfg_attr(feature = "doc", doc(include = "../README.md"))]
//! https://github.com/clap-rs/clap
#![crate_type = "lib"]
#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_import_braces,
    unused_allocation,
    trivial_numeric_casts
)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::{
    build::{App, AppSettings, Arg, ArgGroup, ArgSettings, ValueHint},
    derive::{ArgEnum, Clap, FromArgMatches, IntoApp, Subcommand},
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

#[cfg(feature = "yaml")]
#[cfg_attr(feature = "yaml", doc(hidden))]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[cfg_attr(feature = "derive", doc(hidden))]
pub use clap_derive::{self, *};

#[cfg(feature = "derive")]
#[cfg_attr(feature = "derive", doc(hidden))]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

mod derive;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
<commit_msg>Add derive traits only if derive feature is enabled<commit_after>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature = "doc", feature(external_doc))]
#![doc(html_root_url = "https://docs.rs/clap/3.0.0-beta.1")]
#![cfg_attr(feature = "doc", doc(include = "../README.md"))]
//! https://github.com/clap-rs/clap
#![crate_type = "lib"]
#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_import_braces,
    unused_allocation,
    trivial_numeric_casts
)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::{
    build::{App, AppSettings, Arg, ArgGroup, ArgSettings, ValueHint},
    parse::errors::{Error, ErrorKind, Result},
    parse::{ArgMatches, Indices, OsValues, Values},
};

#[cfg(feature = "derive")]
pub use crate::derive::{ArgEnum, Clap, FromArgMatches, IntoApp, Subcommand};

#[cfg(feature = "yaml")]
#[cfg_attr(feature = "yaml", doc(hidden))]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[cfg_attr(feature = "derive", doc(hidden))]
pub use clap_derive::{self, *};

#[cfg(feature = "derive")]
#[cfg_attr(feature = "derive", doc(hidden))]
pub use lazy_static;

#[macro_use]
#[allow(missing_docs)]
mod macros;

#[cfg(feature = "derive")]
mod derive;

mod build;
mod mkeymap;
mod output;
mod parse;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
<|endoftext|>


<commit_before>//! RethinkDB protocol implementation in Rust.

#![doc(html_root_url="http://rust-rethinkdb.github.io/ql2/1.0.x")]

extern crate protobuf;

pub mod proto;
<commit_msg>Explain how to use the crate<commit_after>//! RethinkDB protocol implementation in Rust
//!
//! This native implementation of the RethinkDB protocol is auto-generated from [ql2.proto] using
//! [protobuf]. The implementation itself is in the [proto] module. Using it is as straight forward
//! as:
//!
//! [ql2.proto]: https://github.com/rethinkdb/rethinkdb/blob/v2.3.1/src/rdb_protocol/ql2.proto
//! [protobuf]: https://crates.io/crates/protobuf
//! [proto]: proto/index.html
//! ```
//! extern crate ql2;
//!
//! use ql2::proto;
//!
//! # fn main() {
//! let version = proto::VersionDummy_Version::V1_0;
//! # }
//! ```

#![doc(html_root_url="http://rust-rethinkdb.github.io/ql2/1.0.x")]

extern crate protobuf;

pub mod proto;
<|endoftext|>


<commit_before>//! Collect an iterator into a slice.
//!
//! Rust comes with the `Iterator::collect` method for collecting an iterator's items into
//! a heap-allocated `Vec` or any other type that implements `FromIterator`, but there's
//! no way to collect items into a stack-allocated array without manually looping over the
//! iterator. This crates provides an alternative with `collect_slice` methods that
//! collect an iterator's items into a mutable slice (of a stack-allocated array or
//! otherwise.)
//!
//! The trait is automatically implemented for any type that implements `Iterator`.
//!
//! # Examples
//!
//! ```
//! use collect_slice::CollectSlice;
//!
//! let mut orig = [0; 8];
//! (0..8).map(|i| i * 2).collect_slice_checked(&mut orig[..]);
//! assert_eq!(orig, [0, 2, 4, 6, 8, 10, 12, 14]);
//!
//! let mut buf = [42; 8];
//! orig.iter()
//!     .map(|&x| x + 10)
//!     .collect_slice_checked(&mut buf[..]);
//! assert_eq!(buf, [10, 12, 14, 16, 18, 20, 22, 24]);
//! ```
//!
//! # Usage
//!
//! This crate can be used through cargo by adding it as a dependency in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! collect_slice = "^1.1.0"
//! ```
//! and importing it in the crate root:
//!
//! ```
//! extern crate collect_slice;
//! ```
//! The provided methods can then be used by importing the trait within individual
//! modules:
//!
//! ```
//! use collect_slice::CollectSlice;
//! ```

/// An iterator that can collect into a slice.
pub trait CollectSlice: Iterator {
    /// Loop through the iterator, sequentially writing items into the given slice until
    /// either the iterator runs out of items or the slice fills up.
    ///
    /// Return the number of items written.
    ///
    /// # Examples
    ///
    /// ```
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Fill a whole slice.
    /// let count = (0..10).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    ///
    /// // Write into a subslice
    /// let count = (10..20).collect_slice(&mut buf[5..7]);
    /// assert_eq!(count, 2);
    /// assert_eq!(buf, [0, 1, 2, 3, 4, 10, 11, 7, 8, 9]);
    ///
    /// // Only writes until iterator is exhausted.
    /// let count = (8..10).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 2);
    /// assert_eq!(buf, [8, 9, 2, 3, 4, 10, 11, 7, 8, 9]);
    ///
    /// // Extra iterator items are ignored.
    /// let count = (20..40).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// assert_eq!(buf, [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
    /// ```
    fn collect_slice(&mut self, slice: &mut [Self::Item]) -> usize;

    /// Perform `collect_slice()` and panic if iterator yielded too few items to fill the
    /// slice.
    ///
    /// If this function succeeds, the number of items written equals the size of the
    /// given slice.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Succeeds as long as entire slice is filled.
    /// (0..20).collect_slice_fill(&mut buf[..]);
    /// (0..5).collect_slice_fill(&mut buf[..5]);
    ///
    /// // Panics otherwise!
    /// (0..5).collect_slice_fill(&mut buf[..]);
    /// ```
    fn collect_slice_fill(&mut self, slice: &mut [Self::Item]) {
        assert_eq!(self.collect_slice(slice), slice.len());
    }

    /// Perform `collect_slice()` and panic if the slice was too small to hold all the
    /// items.
    ///
    /// Return the number of items written.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Succeeds as long as iterator yields all its items.
    /// let count = (0..10).collect_slice_exhaust(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// let count = (0..5).collect_slice_exhaust(&mut buf[..]);
    /// assert_eq!(count, 5);
    ///
    /// // Panics otherwise!
    /// (0..20).collect_slice_exhaust(&mut buf[..]);
    ///
    /// ```
    fn collect_slice_exhaust(&mut self, slice: &mut [Self::Item]) -> usize {
        let count = self.collect_slice(slice);
        assert!(self.next().is_none());
        count
    }

    /// Perform `collect_slice()` and panic if there weren't enough items to fill up
    /// the slice or the slice was too small to hold all the items.
    ///
    /// If this function succeeds, the number of items written equals the size of the
    /// given slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use collect_slice::CollectSlice;
    ///
    /// // Succeeds as long as iterator count equals slice capacity.
    /// let mut buf = [0; 10];
    /// (0..10).collect_slice_checked(&mut buf[..]);
    /// (0..5).collect_slice_checked(&mut buf[2..7]);
    /// ```
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// // Panics if iterator isn't exhausted!
    /// let mut buf = [0; 10];
    /// (0..20).collect_slice_checked(&mut buf[..]);
    /// ```
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// // Panics if slice isn't filled!
    /// let mut buf = [0; 10];
    /// (0..5).collect_slice_checked(&mut buf[..]);
    /// ```
    fn collect_slice_checked(&mut self, slice: &mut [Self::Item]) {
        assert_eq!(self.collect_slice_exhaust(slice), slice.len());
    }
}

impl<T, I: Iterator<Item = T>> CollectSlice for I {
    fn collect_slice(&mut self, slice: &mut [Self::Item]) -> usize {
        slice.iter_mut().zip(self).fold(0, |count, (dest, item)| {
            *dest = item;
            count + 1
        })
    }
}

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

    #[test]
    fn test_basic() {
        let mut buf = [0; 5];

        let count = (0..5).map(|i| {
            i + 1
        }).collect_slice(&mut buf[..]);

        assert_eq!(count, 5);

        assert_eq!(buf[0], 1);
        assert_eq!(buf[1], 2);
        assert_eq!(buf[2], 3);
        assert_eq!(buf[3], 4);
        assert_eq!(buf[4], 5);
    }

    #[test]
    fn test_under() {
        let mut buf = [0; 5];

        let count = (0..3).map(|i| {
            i + 1
        }).collect_slice(&mut buf[1..]);

        assert_eq!(count, 3);

        assert_eq!(buf[0], 0);
        assert_eq!(buf[1], 1);
        assert_eq!(buf[2], 2);
        assert_eq!(buf[3], 3);
        assert_eq!(buf[4], 0);
    }

    #[test]
    fn test_over() {
        let mut buf = [0; 3];

        let mut iter = (0..5).map(|i| {
            i + 1
        });

        let count = iter.collect_slice(&mut buf[..]);

        assert_eq!(count, 3);

        assert_eq!(buf[0], 1);
        assert_eq!(buf[1], 2);
        assert_eq!(buf[2], 3);

        assert_eq!(iter.next().unwrap(), 4);
        assert_eq!(iter.next().unwrap(), 5);
    }

    #[test]
    fn test_checked() {
        let mut buf = [0; 5];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_checked_under() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_checked_over() {
        let mut buf = [0; 3];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    fn test_exhaust() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);

        (0..5).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_exhaust_over() {
        let mut buf = [0; 5];

        (0..7).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);
    }

    #[test]
    fn test_filled() {
        let mut buf = [0; 5];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);

        (0..100).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_filled_under() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);
    }
}
<commit_msg>Allow unsized iterator types<commit_after>//! Collect an iterator into a slice.
//!
//! Rust comes with the `Iterator::collect` method for collecting an iterator's items into
//! a heap-allocated `Vec` or any other type that implements `FromIterator`, but there's
//! no way to collect items into a stack-allocated array without manually looping over the
//! iterator. This crates provides an alternative with `collect_slice` methods that
//! collect an iterator's items into a mutable slice (of a stack-allocated array or
//! otherwise.)
//!
//! The trait is automatically implemented for any type that implements `Iterator`.
//!
//! # Examples
//!
//! ```
//! use collect_slice::CollectSlice;
//!
//! let mut orig = [0; 8];
//! (0..8).map(|i| i * 2).collect_slice_checked(&mut orig[..]);
//! assert_eq!(orig, [0, 2, 4, 6, 8, 10, 12, 14]);
//!
//! let mut buf = [42; 8];
//! orig.iter()
//!     .map(|&x| x + 10)
//!     .collect_slice_checked(&mut buf[..]);
//! assert_eq!(buf, [10, 12, 14, 16, 18, 20, 22, 24]);
//! ```
//!
//! # Usage
//!
//! This crate can be used through cargo by adding it as a dependency in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! collect_slice = "^1.1.0"
//! ```
//! and importing it in the crate root:
//!
//! ```
//! extern crate collect_slice;
//! ```
//! The provided methods can then be used by importing the trait within individual
//! modules:
//!
//! ```
//! use collect_slice::CollectSlice;
//! ```

/// An iterator that can collect into a slice.
pub trait CollectSlice: Iterator {
    /// Loop through the iterator, sequentially writing items into the given slice until
    /// either the iterator runs out of items or the slice fills up.
    ///
    /// Return the number of items written.
    ///
    /// # Examples
    ///
    /// ```
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Fill a whole slice.
    /// let count = (0..10).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    ///
    /// // Write into a subslice
    /// let count = (10..20).collect_slice(&mut buf[5..7]);
    /// assert_eq!(count, 2);
    /// assert_eq!(buf, [0, 1, 2, 3, 4, 10, 11, 7, 8, 9]);
    ///
    /// // Only writes until iterator is exhausted.
    /// let count = (8..10).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 2);
    /// assert_eq!(buf, [8, 9, 2, 3, 4, 10, 11, 7, 8, 9]);
    ///
    /// // Extra iterator items are ignored.
    /// let count = (20..40).collect_slice(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// assert_eq!(buf, [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
    /// ```
    fn collect_slice(&mut self, slice: &mut [Self::Item]) -> usize;

    /// Perform `collect_slice()` and panic if iterator yielded too few items to fill the
    /// slice.
    ///
    /// If this function succeeds, the number of items written equals the size of the
    /// given slice.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Succeeds as long as entire slice is filled.
    /// (0..20).collect_slice_fill(&mut buf[..]);
    /// (0..5).collect_slice_fill(&mut buf[..5]);
    ///
    /// // Panics otherwise!
    /// (0..5).collect_slice_fill(&mut buf[..]);
    /// ```
    fn collect_slice_fill(&mut self, slice: &mut [Self::Item]) {
        assert_eq!(self.collect_slice(slice), slice.len());
    }

    /// Perform `collect_slice()` and panic if the slice was too small to hold all the
    /// items.
    ///
    /// Return the number of items written.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// let mut buf = [0; 10];
    ///
    /// // Succeeds as long as iterator yields all its items.
    /// let count = (0..10).collect_slice_exhaust(&mut buf[..]);
    /// assert_eq!(count, 10);
    /// let count = (0..5).collect_slice_exhaust(&mut buf[..]);
    /// assert_eq!(count, 5);
    ///
    /// // Panics otherwise!
    /// (0..20).collect_slice_exhaust(&mut buf[..]);
    ///
    /// ```
    fn collect_slice_exhaust(&mut self, slice: &mut [Self::Item]) -> usize {
        let count = self.collect_slice(slice);
        assert!(self.next().is_none());
        count
    }

    /// Perform `collect_slice()` and panic if there weren't enough items to fill up
    /// the slice or the slice was too small to hold all the items.
    ///
    /// If this function succeeds, the number of items written equals the size of the
    /// given slice.
    ///
    /// # Examples
    ///
    /// ```
    /// use collect_slice::CollectSlice;
    ///
    /// // Succeeds as long as iterator count equals slice capacity.
    /// let mut buf = [0; 10];
    /// (0..10).collect_slice_checked(&mut buf[..]);
    /// (0..5).collect_slice_checked(&mut buf[2..7]);
    /// ```
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// // Panics if iterator isn't exhausted!
    /// let mut buf = [0; 10];
    /// (0..20).collect_slice_checked(&mut buf[..]);
    /// ```
    /// ```rust,should_panic
    /// use collect_slice::CollectSlice;
    ///
    /// // Panics if slice isn't filled!
    /// let mut buf = [0; 10];
    /// (0..5).collect_slice_checked(&mut buf[..]);
    /// ```
    fn collect_slice_checked(&mut self, slice: &mut [Self::Item]) {
        assert_eq!(self.collect_slice_exhaust(slice), slice.len());
    }
}

impl<I: ?Sized> CollectSlice for I where I: Iterator {
    fn collect_slice(&mut self, slice: &mut [Self::Item]) -> usize {
        slice.iter_mut().zip(self).fold(0, |count, (dest, item)| {
            *dest = item;
            count + 1
        })
    }
}

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

    #[test]
    fn test_basic() {
        let mut buf = [0; 5];

        let count = (0..5).map(|i| {
            i + 1
        }).collect_slice(&mut buf[..]);

        assert_eq!(count, 5);

        assert_eq!(buf[0], 1);
        assert_eq!(buf[1], 2);
        assert_eq!(buf[2], 3);
        assert_eq!(buf[3], 4);
        assert_eq!(buf[4], 5);
    }

    #[test]
    fn test_under() {
        let mut buf = [0; 5];

        let count = (0..3).map(|i| {
            i + 1
        }).collect_slice(&mut buf[1..]);

        assert_eq!(count, 3);

        assert_eq!(buf[0], 0);
        assert_eq!(buf[1], 1);
        assert_eq!(buf[2], 2);
        assert_eq!(buf[3], 3);
        assert_eq!(buf[4], 0);
    }

    #[test]
    fn test_over() {
        let mut buf = [0; 3];

        let mut iter = (0..5).map(|i| {
            i + 1
        });

        let count = iter.collect_slice(&mut buf[..]);

        assert_eq!(count, 3);

        assert_eq!(buf[0], 1);
        assert_eq!(buf[1], 2);
        assert_eq!(buf[2], 3);

        assert_eq!(iter.next().unwrap(), 4);
        assert_eq!(iter.next().unwrap(), 5);
    }

    #[test]
    fn test_checked() {
        let mut buf = [0; 5];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_checked_under() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_checked_over() {
        let mut buf = [0; 3];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_checked(&mut buf[..]);
    }

    #[test]
    fn test_exhaust() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);

        (0..5).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_exhaust_over() {
        let mut buf = [0; 5];

        (0..7).map(|i| {
            i + 1
        }).collect_slice_exhaust(&mut buf[..]);
    }

    #[test]
    fn test_filled() {
        let mut buf = [0; 5];

        (0..5).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);

        (0..100).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);
    }

    #[test]
    #[should_panic]
    fn test_filled_under() {
        let mut buf = [0; 5];

        (0..3).map(|i| {
            i + 1
        }).collect_slice_fill(&mut buf[..]);
    }

    #[test]
    fn test_unsized() {
        let mut buf = [0; 5];

        let it: &mut Iterator<Item=_> = &mut (0..5).map(|i| {
            i + 1
        });
        let count = <Iterator<Item=_> as CollectSlice>::collect_slice(it, &mut buf[..]);

        assert_eq!(count, 5);

        assert_eq!(buf[0], 1);
        assert_eq!(buf[1], 2);
        assert_eq!(buf[2], 3);
        assert_eq!(buf[3], 4);
        assert_eq!(buf[4], 5);
    }
}
<|endoftext|>


<commit_before>//! # A wrapper for libxml2
//! This library provides an interface to a subset of the libxml API.
//! The idea is to extend it whenever more functionality is needed.
//! Providing a more or less complete wrapper would be too much work.

extern crate libc;

use std::ffi::CString;
use std::fmt;

use libc::{c_char, c_void, c_int};

#[link(name = "xml2")]
extern "C" {
    fn xmlParseFile(filename: *const c_char) -> *mut c_void;
    fn xmlSaveFile(filename: *const c_char, cur: *mut c_void) -> c_int;
}

///An xml document
pub struct XmlDoc {
    ///It's libxml's xmlDocPtr
    xml_doc_ptr : *mut c_void,
}

///Parser Errors
pub enum XmlParseError {
    ///Parsing returned a null pointer as document pointer
    GotNullPointer,
}

impl fmt::Debug for XmlParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            XmlParseError::GotNullPointer => write!(f, "Got a Null pointer")
        }
    }
}

impl XmlDoc {
    ///parses the file `filename` to generate a new `XmlDoc`
    pub fn parse_file(filename : &str) -> std::result::Result<XmlDoc, XmlParseError> {
        let c_filename = CString::new(filename).unwrap().as_ptr();
        unsafe {
            let docptr = xmlParseFile(c_filename);
            if docptr.is_null() {
                return Err(XmlParseError::GotNullPointer);
            }
            Ok(XmlDoc {
                xml_doc_ptr : docptr
            })
        }
    }

    ///Write document to `filename`
    pub fn save_file(&self, filename : &str) -> Result<c_int, ()> {
        let c_filename = CString::new(filename).unwrap().as_ptr();
        unsafe {
            let retval = xmlSaveFile(c_filename, self.xml_doc_ptr);
            if retval < 0 {
                return Err(());
            }
            Ok(retval)
        }
    }
}

<commit_msg>Memory can now be freed<commit_after>//! # A wrapper for libxml2
//! This library provides an interface to a subset of the libxml API.
//! The idea is to extend it whenever more functionality is needed.
//! Providing a more or less complete wrapper would be too much work.

extern crate libc;

use std::ffi::CString;
use std::fmt;

use libc::{c_char, c_void, c_int};

#[link(name = "xml2")]
extern "C" {
    fn xmlParseFile(filename: *const c_char) -> *mut c_void;
    fn xmlSaveFile(filename: *const c_char, cur: *mut c_void) -> c_int;
    fn xmlFreeDoc(cur: *mut c_void);
    fn xmlCleanupParser();
}

///Parser Errors
pub enum XmlParseError {
    ///Parsing returned a null pointer as document pointer
    GotNullPointer,
}

impl fmt::Debug for XmlParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            XmlParseError::GotNullPointer => write!(f, "Got a Null pointer")
        }
    }
}

///An xml document
pub struct XmlDoc {
    ///It's libxml's xmlDocPtr
    xml_doc_ptr : *mut c_void,
}

impl Drop for XmlDoc {
    ///Free document when it goes out of scope
    fn drop(&mut self) {
        unsafe {
            xmlFreeDoc(self.xml_doc_ptr);
        }
    }
}

impl XmlDoc {
    ///Parses the file `filename` to generate a new `XmlDoc`
    pub fn parse_file(filename : &str) -> std::result::Result<XmlDoc, XmlParseError> {
        let c_filename = CString::new(filename).unwrap().as_ptr();
        unsafe {
            let docptr = xmlParseFile(c_filename);
            if docptr.is_null() {
                return Err(XmlParseError::GotNullPointer);
            }
            Ok(XmlDoc {
                xml_doc_ptr : docptr
            })
        }
    }

    ///Write document to `filename`
    pub fn save_file(&self, filename : &str) -> Result<c_int, ()> {
        let c_filename = CString::new(filename).unwrap().as_ptr();
        unsafe {
            let retval = xmlSaveFile(c_filename, self.xml_doc_ptr);
            if retval < 0 {
                return Err(());
            }
            Ok(retval)
        }
    }
}

///Free global memory of parser
///Do not call this function before all parsing is done!
pub fn xml_cleanup_parser() {
    unsafe {
        xmlCleanupParser();
    }
}
<|endoftext|>


<commit_before>//!
//!
//! A library for creating interactive command line shells
#[macro_use] extern crate prettytable;
use prettytable::Table;
use prettytable::format;

use std::io;
use std::io::prelude::*;
use std::string::ToString;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};

use std::collections::BTreeMap;

/// Command execution error
#[derive(Debug)]
pub enum ExecError {
    /// Empty command provided
    Empty,
    /// Exit from the shell loop
    Quit,
    /// Some arguments are missing
    MissingArgs,
    /// The provided command is unknown
    UnknownCommand(String),
    /// The history index is not valid
    InvalidHistory(usize),
    /// Other error that may have happen during command execution
    Other(Box<Error>),
}
use ExecError::*;

impl fmt::Display for ExecError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        return match self {
            &Empty => write!(format, "No command provided"),
            &Quit => write!(format, "Quit"),
            &UnknownCommand(ref cmd) => write!(format, "Unknown Command {}", cmd),
            &InvalidHistory(i) => write!(format, "Invalid history entry {}", i),
            &MissingArgs => write!(format, "Not enough arguments"),
            &Other(ref e) => write!(format, "{}", e)
        };
    }
}

// impl Error for ExecError {
//     fn description(&self) -> &str {
//         return match self {
//             &Quit => "The command requested to quit",
//             &UnknownCommand(..) => "The provided command is unknown",
//             &MissingArgs => "Not enough arguments have been provided",
//             &Other(..) => "Other error occured"
//         };
//     }
// }

impl <E: Error + 'static> From<E> for ExecError {
    fn from(e: E) -> ExecError {
        return Other(Box::new(e));
    }
}

/// Input / Output for shell execution
#[derive(Clone)]
pub struct ShellIO {
    input: Arc<Mutex<io::Read + Send>>,
    output: Arc<Mutex<io::Write + Send>>
}

impl ShellIO {
    /// Create a new Shell I/O wrapping provided Input and Output
    pub fn new(input: I, output: O) -> ShellIO
        where I: Read + Send + 'static, O: Write + Send + 'static
    {
        return ShellIO {
            input: Arc::new(Mutex::new(input)),
            output: Arc::new(Mutex::new(output))
        };
    }

    /// Create a new Shell I/O wrapping provided Read/Write io
    pub fn new_io<T>(io: T) -> ShellIO
        where T: Read + Write + Send + 'static
    {
        let io = Arc::new(Mutex::new(io));
        return ShellIO {
            input: io.clone(),
            output: io
        };
    }
}

impl Read for ShellIO {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.input.lock().expect("Cannot get handle to console input").read(buf);
    }
}

impl Write for ShellIO {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.output.lock().expect("Cannot get handle to console output").write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.output.lock().expect("Cannot get handle to console output").flush();
    }
}

impl Default for ShellIO {
    fn default() -> Self {
        return Self::new(io::stdin(), io::stdout());
    }
}

/// Result from command execution
pub type ExecResult = Result<(), ExecError>;

/// A shell
pub struct Shell<T> {
    commands: BTreeMap<String, Arc<builtins::Command<T>>>,
    default: Arc<Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync>,
    data: T,
    prompt: String,
    history: History
}

impl <T> Shell<T> {
    /// Create a new shell, wrapping `data`, using provided IO
    pub fn new(data: T) -> Shell<T> {
        let mut sh = Shell {
            commands: BTreeMap::new(),
            default: Arc::new(|_, _, cmd| Err(UnknownCommand(cmd.to_string()))),
            data: data,
            prompt: String::from(">"),
            history: History::new(10),
        };
        sh.register_command(builtins::help_cmd());
        sh.register_command(builtins::quit_cmd());
        sh.register_command(builtins::history_cmd());
        return sh;
    }

    /// Get a mutable pointer to the inner data
    pub fn data(&mut self) -> &mut T {
        return &mut self.data;
    }

    /// Change the current prompt
    pub fn set_prompt(&mut self, prompt: String) {
        self.prompt = prompt;
    }

    fn register_command(&mut self, cmd: builtins::Command<T>) {
        self.commands.insert(cmd.name.clone(), Arc::new(cmd));
    }

    // Set a custom default handler, invoked when a command is not found
    pub fn set_default<F>(&mut self, func: F)
        where F: Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync + 'static
    {
        self.default = Arc::new(func);
    }

    /// Register a shell command.
    /// Shell commands get called with a reference to the current shell
    pub fn new_shell_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.register_command(builtins::Command::new(name.to_string(), description.to_string(), nargs, Box::new(func)));
    }

    /// Register a command
    pub fn new_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, nargs, move |io, sh, args| func(io, sh.data(), args));
    }

    /// Register a command that do not accept any argument
    pub fn new_command_noargs<S, F>(&mut self, name: S, description: S, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, 0, move |io, sh, _| func(io, sh.data()));
    }

    /// Print the help to stdout
    pub fn print_help(&self, io: &mut ShellIO) -> ExecResult {
        let mut table = Table::new();
        table.set_format(*format::consts::FORMAT_CLEAN);
        for cmd in self.commands.values() {
            table.add_row(cmd.help());
        }
        return table.print(io).map_err(|e| From::from(e))
    }

    /// Return the command history
    pub fn get_history(&self) -> &History {
        return &self.history;
    }

    /// Evaluate a command line
    pub fn eval(&mut self, io: &mut ShellIO, line: &str) -> ExecResult {
        let mut splt = line.trim().split_whitespace();
        return match splt.next() {
            None => Err(Empty),
            Some(cmd) => match self.commands.get(cmd).map(|i| i.clone()) {
                None => self.default.clone()(io, self, line),
                Some(c) => c.run(io, self, &splt.collect::<Vec<&str>>())
            }
        };
    }

    fn print_prompt(&self, io: &mut ShellIO) {
        write!(io, "{}", self.prompt).unwrap();
        io.flush().unwrap();
    }

    /// Enter the shell main loop, exiting only when
    /// the "quit" command is called
    pub fn run_loop(&mut self, io: &mut ShellIO) {
        self.print_prompt(io);
        let stdin = io::BufReader::new(io.clone());

        for line in stdin.lines().map(|l| l.unwrap()) {
            if let Err(e) = self.eval(io, &line) {
                match e {
                    Empty => {},
                    Quit => return,
                    e @ _ => writeln!(io, "Error : {}", e).unwrap()
                };
            } else {
                self.get_history().push(line);
            }
            self.print_prompt(io);
        }
    }
}

impl <T> Deref for Shell<T> {
    type Target = T;
    fn deref(&self) -> &T {
        return &self.data;
    }
}

impl <T> DerefMut for Shell<T> {
    fn deref_mut(&mut self) -> &mut T {
        return &mut self.data;
    }
}

impl <T> Clone for Shell<T> where T: Clone {
    fn clone(&self) -> Self {
        return Shell {
            commands: self.commands.clone(),
            default: self.default.clone(),
            data: self.data.clone(),
            prompt: self.prompt.clone(),
            history: self.history.clone()
        };
    }
}

/// Wrap the command history from a shell.
/// It has a maximum capacity, and when max capacity is reached,
/// less recent command is removed from history
#[derive(Clone)]
pub struct History {
    history: Arc<Mutex<Vec<String>>>,
    capacity: usize
}

impl History {
    /// Create a new history with the given capacity
    fn new(capacity: usize) -> History {
        return History {
            history: Arc::new(Mutex::new(Vec::with_capacity(capacity))),
            capacity: capacity
        };
    }

    /// Push a command to the history, removing the oldest
    /// one if maximum capacity has been reached
    fn push(&self, cmd: String) {
        let mut hist = self.history.lock().unwrap();
        if hist.len() >= self.capacity {
            hist.remove(0);
        }
        hist.push(cmd);
    }

    /// Print the history to stdout
    pub fn print<T: Write>(&self, out: &mut T) {
        let mut cnt = 0;
        for s in &*self.history.lock().unwrap() {
            writeln!(out, "{}: {}", cnt, s).expect("Cannot write to output");
            cnt += 1;
        }
    }

    /// Get a command from history by its index
    pub fn get(&self, i: usize) -> Option<String> {
        return self.history.lock().unwrap().get(i).map(|s| s.clone());
    }
}

mod builtins {
    use std::str::FromStr;
    use prettytable::row::Row;
    use super::{Shell, ShellIO, ExecError, ExecResult};

    pub type CmdFn<T> = Box<Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync>;

    pub struct Command<T> {
        pub name: String,
        description: String,
        nargs: usize,
        func: CmdFn<T>
    }

    impl <T> Command<T> {
        pub fn new(name: String, description: String, nargs: usize, func: CmdFn<T>) -> Command<T> {
            return Command {
                name: name,
                description: description,
                nargs: nargs,
                func: func
            };
        }

        pub fn help(&self) -> Row {
            return row![self.name, ":", self.description];
        }

        pub fn run(&self, io: &mut ShellIO, shell: &mut Shell<T>, args: &[&str]) -> ExecResult {
            if args.len() < self.nargs {
                return Err(ExecError::MissingArgs);
            }
            return (self.func)(io, shell, args);
        }
    }

    pub fn help_cmd<T>() -> Command<T> {
        return Command::new("help".to_string(), "Print this help".to_string(), 0, Box::new(|io, shell, _| shell.print_help(io)));
    }

    pub fn quit_cmd<T>() -> Command<T> {
        return Command::new("quit".to_string(), "Quit".to_string(), 0, Box::new(|_, _, _| Err(ExecError::Quit)));
    }

    pub fn history_cmd<T>() -> Command<T> {
        return Command::new("history".to_string(), "Print commands history or run a command from it".to_string(), 0, Box::new(|io, shell, args| {
            if args.len() > 0 {
                let i = try!(usize::from_str(args[0]));
                let cmd = try!(shell.get_history().get(i).ok_or(ExecError::InvalidHistory(i)));
                return shell.eval(io, &cmd);
            } else {
                shell.get_history().print(io);
                return Ok(());
            }
        }));
    }
}
<commit_msg>Support for multi-line commands<commit_after>//!
//!
//! A library for creating interactive command line shells
#[macro_use] extern crate prettytable;
use prettytable::Table;
use prettytable::format;

use std::io;
use std::io::prelude::*;
use std::string::ToString;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};

use std::collections::BTreeMap;

/// Command execution error
#[derive(Debug)]
pub enum ExecError {
    /// Empty command provided
    Empty,
    /// Exit from the shell loop
    Quit,
    /// Some arguments are missing
    MissingArgs,
    /// The provided command is unknown
    UnknownCommand(String),
    /// The history index is not valid
    InvalidHistory(usize),
    /// Other error that may have happen during command execution
    Other(Box<Error>),
}
use ExecError::*;

impl fmt::Display for ExecError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        return match self {
            &Empty => write!(format, "No command provided"),
            &Quit => write!(format, "Quit"),
            &UnknownCommand(ref cmd) => write!(format, "Unknown Command {}", cmd),
            &InvalidHistory(i) => write!(format, "Invalid history entry {}", i),
            &MissingArgs => write!(format, "Not enough arguments"),
            &Other(ref e) => write!(format, "{}", e)
        };
    }
}

// impl Error for ExecError {
//     fn description(&self) -> &str {
//         return match self {
//             &Quit => "The command requested to quit",
//             &UnknownCommand(..) => "The provided command is unknown",
//             &MissingArgs => "Not enough arguments have been provided",
//             &Other(..) => "Other error occured"
//         };
//     }
// }

impl <E: Error + 'static> From<E> for ExecError {
    fn from(e: E) -> ExecError {
        return Other(Box::new(e));
    }
}

/// Input / Output for shell execution
#[derive(Clone)]
pub struct ShellIO {
    input: Arc<Mutex<io::Read + Send>>,
    output: Arc<Mutex<io::Write + Send>>
}

impl ShellIO {
    /// Create a new Shell I/O wrapping provided Input and Output
    pub fn new(input: I, output: O) -> ShellIO
        where I: Read + Send + 'static, O: Write + Send + 'static
    {
        return ShellIO {
            input: Arc::new(Mutex::new(input)),
            output: Arc::new(Mutex::new(output))
        };
    }

    /// Create a new Shell I/O wrapping provided Read/Write io
    pub fn new_io<T>(io: T) -> ShellIO
        where T: Read + Write + Send + 'static
    {
        let io = Arc::new(Mutex::new(io));
        return ShellIO {
            input: io.clone(),
            output: io
        };
    }
}

impl Read for ShellIO {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.input.lock().expect("Cannot get handle to console input").read(buf);
    }
}

impl Write for ShellIO {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.output.lock().expect("Cannot get handle to console output").write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.output.lock().expect("Cannot get handle to console output").flush();
    }
}

impl Default for ShellIO {
    fn default() -> Self {
        return Self::new(io::stdin(), io::stdout());
    }
}

/// Result from command execution
pub type ExecResult = Result<(), ExecError>;

/// A shell
pub struct Shell<T> {
    commands: BTreeMap<String, Arc<builtins::Command<T>>>,
    default: Arc<Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync>,
    data: T,
    prompt: String,
    unclosed_prompt: String,
    history: History
}

impl <T> Shell<T> {
    /// Create a new shell, wrapping `data`, using provided IO
    pub fn new(data: T) -> Shell<T> {
        let mut sh = Shell {
            commands: BTreeMap::new(),
            default: Arc::new(|_, _, cmd| Err(UnknownCommand(cmd.to_string()))),
            data: data,
            prompt: String::from(">"),
            unclosed_prompt: String::from(">"),
            history: History::new(10),
        };
        sh.register_command(builtins::help_cmd());
        sh.register_command(builtins::quit_cmd());
        sh.register_command(builtins::history_cmd());
        return sh;
    }

    /// Get a mutable pointer to the inner data
    pub fn data(&mut self) -> &mut T {
        return &mut self.data;
    }

    /// Change the current prompt
    pub fn set_prompt(&mut self, prompt: String) {
        self.prompt = prompt;
    }

    /// Change the current unclosed prompt
    pub fn set_unclosed_prompt(&mut self, prompt: String) {
        self.unclosed_prompt = prompt;
    }

    fn register_command(&mut self, cmd: builtins::Command<T>) {
        self.commands.insert(cmd.name.clone(), Arc::new(cmd));
    }

    // Set a custom default handler, invoked when a command is not found
    pub fn set_default<F>(&mut self, func: F)
        where F: Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync + 'static
    {
        self.default = Arc::new(func);
    }

    /// Register a shell command.
    /// Shell commands get called with a reference to the current shell
    pub fn new_shell_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.register_command(builtins::Command::new(name.to_string(), description.to_string(), nargs, Box::new(func)));
    }

    /// Register a command
    pub fn new_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, nargs, move |io, sh, args| func(io, sh.data(), args));
    }

    /// Register a command that do not accept any argument
    pub fn new_command_noargs<S, F>(&mut self, name: S, description: S, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, 0, move |io, sh, _| func(io, sh.data()));
    }

    /// Print the help to stdout
    pub fn print_help(&self, io: &mut ShellIO) -> ExecResult {
        let mut table = Table::new();
        table.set_format(*format::consts::FORMAT_CLEAN);
        for cmd in self.commands.values() {
            table.add_row(cmd.help());
        }
        return table.print(io).map_err(|e| From::from(e))
    }

    /// Return the command history
    pub fn get_history(&self) -> &History {
        return &self.history;
    }

    /// Evaluate a command line
    pub fn eval(&mut self, io: &mut ShellIO, line: &str) -> ExecResult {
        let mut splt = line.trim().split_whitespace();
        return match splt.next() {
            None => Err(Empty),
            Some(cmd) => match self.commands.get(cmd).map(|i| i.clone()) {
                None => self.default.clone()(io, self, line),
                Some(c) => c.run(io, self, &splt.collect::<Vec<&str>>())
            }
        };
    }

    fn print_prompt(&self, io: &mut ShellIO, unclosed: bool) {
        if unclosed {
            write!(io, "{} ", self.unclosed_prompt).unwrap();
        } else {
            write!(io, "{} ", self.prompt).unwrap();
        }
        io.flush().unwrap();
    }

    /// Enter the shell main loop, exiting only when
    /// the "quit" command is called
    pub fn run_loop(&mut self, io: &mut ShellIO) {
        self.print_prompt(io, false);
        let stdin = io::BufReader::new(io.clone());
        let mut iter = stdin.lines().map(|l| l.unwrap());
        while let Some(mut line) = iter.next() {
            while &line[line.len()-1 ..] == "\\" {
                self.print_prompt(io, true);
                line.pop();
                line.push_str(&iter.next().unwrap())
            }
            if let Err(e) = self.eval(io, &line) {
                match e {
                    Empty => {},
                    Quit => return,
                    e @ _ => writeln!(io, "Error : {}", e).unwrap()
                };
            } else {
                self.get_history().push(line);
            }
            self.print_prompt(io, false);
        }
    }
}

impl <T> Deref for Shell<T> {
    type Target = T;
    fn deref(&self) -> &T {
        return &self.data;
    }
}

impl <T> DerefMut for Shell<T> {
    fn deref_mut(&mut self) -> &mut T {
        return &mut self.data;
    }
}

impl <T> Clone for Shell<T> where T: Clone {
    fn clone(&self) -> Self {
        return Shell {
            commands: self.commands.clone(),
            default: self.default.clone(),
            data: self.data.clone(),
            prompt: self.prompt.clone(),
            unclosed_prompt: self.unclosed_prompt.clone(),
            history: self.history.clone()
        };
    }
}

/// Wrap the command history from a shell.
/// It has a maximum capacity, and when max capacity is reached,
/// less recent command is removed from history
#[derive(Clone)]
pub struct History {
    history: Arc<Mutex<Vec<String>>>,
    capacity: usize
}

impl History {
    /// Create a new history with the given capacity
    fn new(capacity: usize) -> History {
        return History {
            history: Arc::new(Mutex::new(Vec::with_capacity(capacity))),
            capacity: capacity
        };
    }

    /// Push a command to the history, removing the oldest
    /// one if maximum capacity has been reached
    fn push(&self, cmd: String) {
        let mut hist = self.history.lock().unwrap();
        if hist.len() >= self.capacity {
            hist.remove(0);
        }
        hist.push(cmd);
    }

    /// Print the history to stdout
    pub fn print<T: Write>(&self, out: &mut T) {
        let mut cnt = 0;
        for s in &*self.history.lock().unwrap() {
            writeln!(out, "{}: {}", cnt, s).expect("Cannot write to output");
            cnt += 1;
        }
    }

    /// Get a command from history by its index
    pub fn get(&self, i: usize) -> Option<String> {
        return self.history.lock().unwrap().get(i).map(|s| s.clone());
    }
}

mod builtins {
    use std::str::FromStr;
    use prettytable::row::Row;
    use super::{Shell, ShellIO, ExecError, ExecResult};

    pub type CmdFn<T> = Box<Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync>;

    pub struct Command<T> {
        pub name: String,
        description: String,
        nargs: usize,
        func: CmdFn<T>
    }

    impl <T> Command<T> {
        pub fn new(name: String, description: String, nargs: usize, func: CmdFn<T>) -> Command<T> {
            return Command {
                name: name,
                description: description,
                nargs: nargs,
                func: func
            };
        }

        pub fn help(&self) -> Row {
            return row![self.name, ":", self.description];
        }

        pub fn run(&self, io: &mut ShellIO, shell: &mut Shell<T>, args: &[&str]) -> ExecResult {
            if args.len() < self.nargs {
                return Err(ExecError::MissingArgs);
            }
            return (self.func)(io, shell, args);
        }
    }

    pub fn help_cmd<T>() -> Command<T> {
        return Command::new("help".to_string(), "Print this help".to_string(), 0, Box::new(|io, shell, _| shell.print_help(io)));
    }

    pub fn quit_cmd<T>() -> Command<T> {
        return Command::new("quit".to_string(), "Quit".to_string(), 0, Box::new(|_, _, _| Err(ExecError::Quit)));
    }

    pub fn history_cmd<T>() -> Command<T> {
        return Command::new("history".to_string(), "Print commands history or run a command from it".to_string(), 0, Box::new(|io, shell, args| {
            if args.len() > 0 {
                let i = try!(usize::from_str(args[0]));
                let cmd = try!(shell.get_history().get(i).ok_or(ExecError::InvalidHistory(i)));
                return shell.eval(io, &cmd);
            } else {
                shell.get_history().print(io);
                return Ok(());
            }
        }));
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::{mem, ops};
use std::iter::{Iterator, IntoIterator};

#[derive(Clone)]
pub struct Slab<T> {
    num_elems: usize,
    buf: Vec<Option<T>>
}

impl<T> Slab<T> {
    pub fn new(capacity: usize) -> Slab<T> {
        let mut buf = Vec::<Option<T>>::with_capacity(capacity);
        for _ in 0..capacity {
            buf.push(None);
        }

        Slab {
            num_elems: 0,
            buf: buf
        }
    }

    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.buf.len() {
            let extra_mem = self.num_elems * 2;
            self.allocate_exact(extra_mem);
        }

        self.buf[self.num_elems] = Some(elem);

        // Update counts
        self.num_elems += 1;
    }

    #[inline]
    pub fn remove(&mut self, offset: usize) -> Option<T> {
        self.num_elems -= 1;

        // Removal of only element
        if self.num_elems == 0 {
            return mem::replace(&mut self.buf[0], None);
        }

        // Removal of last element in buf
        if offset == self.num_elems {
            return mem::replace(&mut self.buf[self.num_elems], None);
        }

        // Removal of any other element
        self.buf.swap(offset, self.num_elems);
        mem::replace(&mut self.buf[self.num_elems], None)
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.num_elems
    }

    #[inline]
    fn allocate_exact(&mut self, size: usize) {
        // Allocate extra space inside buffer
        self.buf.reserve_exact(size);

        // Fill the extra space with tombstones
        for _ in 0..size {
            self.buf.push(None);
        }
    }

    #[inline]
    pub fn iter(&self) -> SlabIter<T>  {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter {
            iter: self.iter()
        }
    }
}

impl<T> ops::Index<usize> for Slab<T> {
    type Output = Option<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &(self.buf[index])
    }
}

impl<T> ops::IndexMut<usize> for Slab<T> {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Option<T> {
        &mut (self.buf[index])
    }
}

pub struct SlabIter<'a, T: 'a> {
    current_offset: usize,
    slab: &'a Slab<T>
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            match self.slab.buf[self.current_offset] {
                Some(ref elem) => {
                    self.current_offset += 1;
                    return Some(elem);
                }
                None => self.current_offset += 1
            }
        }

        None
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}

unsafe impl<T: Send> Send for Slab<T> {}
unsafe impl<T: Sync> Sync for Slab<T> {}
<commit_msg>Docs added<commit_after>// Copyright 2016 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! simple_slab provides a fast, minimal, slab allocator.
//! ## Usage
//!
//! ```no_run
//! extern crate simple_slab;
//!
//! use simple_slab::Slab;
//!
//! fn main() {
//!     const MAX_ELEMS: usize = 100000;
//!
//!     let mut slab = Slab::<u32>::new(MAX_ELEMS);
//!
//!     // Insertion
//!     for num in 0..MAX_ELEMS {
//!         slab.insert(num as u32);
//!     }
//!
//!     // Traversal
//!     for offset in 0..slab.len() {
//!         match slab[offset] {
//!             Some(num) => {
//!                 // Stuff...
//!             }
//!             None => {
//!                 // Stuff...
//!             }
//!         }
//!     }
//!
//!     // Iteration
//!     for num in slab.iter() {
//!         // Stuff...
//!     }
//!
//!     // Removal
//!     for offset in 0..slab.len() {
//!         let num = slab.remove(offset).unwrap();
//!     }
//! }
//! ```

use std::{mem, ops};
use std::iter::{Iterator, IntoIterator};

#[derive(Clone)]
/// Pre-allocated chunk of memory sized specifically for `T`
pub struct Slab<T> {
    num_elems: usize,
    buf: Vec<Option<T>>
}

impl<T> Slab<T> {
    /// Creates a new Slab with initial room without re-allocation for `capacity` num elements.
    pub fn new(capacity: usize) -> Slab<T> {
        let mut buf = Vec::<Option<T>>::with_capacity(capacity);
        for _ in 0..capacity {
            buf.push(None);
        }

        Slab {
            num_elems: 0,
            buf: buf
        }
    }

    /// Inserts a new element into the slab, re-allocating if neccessary.
    ///
    /// # Panics
    /// Panics if re-allocation overflows `usize`.
    #[inline]
    pub fn insert(&mut self, elem: T) {
        if self.num_elems == self.buf.len() {
            let extra_mem = self.num_elems * 2;
            self.allocate_exact(extra_mem);
        }

        self.buf[self.num_elems] = Some(elem);

        // Update counts
        self.num_elems += 1;
    }

    /// Remove the element at `offset`.
    ///
    /// # Panics
    /// Panics if `offset` is out of bounds.
    #[inline]
    pub fn remove(&mut self, offset: usize) -> Option<T> {
        self.num_elems -= 1;

        // Removal of only element
        if self.num_elems == 0 {
            return mem::replace(&mut self.buf[0], None);
        }

        // Removal of last element in buf
        if offset == self.num_elems {
            return mem::replace(&mut self.buf[self.num_elems], None);
        }

        // Removal of any other element
        self.buf.swap(offset, self.num_elems);
        mem::replace(&mut self.buf[self.num_elems], None)
    }

    /// Returns the number of elements in the slab.
    #[inline]
    pub fn len(&self) -> usize {
        self.num_elems
    }

    /// Returns an iterator over the slab.
    #[inline]
    pub fn iter(&self) -> SlabIter<T>  {
        SlabIter {
            slab: self,
            current_offset: 0
        }
    }

    /// Returns a mutable iterator over the slab
    #[inline]
    pub fn iter_mut(&mut self) -> SlabMutIter<T> {
        SlabMutIter {
            iter: self.iter()
        }
    }

    #[inline]
    fn allocate_exact(&mut self, size: usize) {
        // Allocate extra space inside buffer
        self.buf.reserve_exact(size);

        // Fill the extra space with tombstones
        for _ in 0..size {
            self.buf.push(None);
        }
    }
}

impl<T> ops::Index<usize> for Slab<T> {
    type Output = Option<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &(self.buf[index])
    }
}

impl<T> ops::IndexMut<usize> for Slab<T> {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Option<T> {
        &mut (self.buf[index])
    }
}

pub struct SlabIter<'a, T: 'a> {
    current_offset: usize,
    slab: &'a Slab<T>
}

pub struct SlabMutIter<'a, T: 'a> {
    iter: SlabIter<'a, T>
}

impl<'a, T> Iterator for SlabIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        while self.current_offset < self.slab.len() {
            match self.slab.buf[self.current_offset] {
                Some(ref elem) => {
                    self.current_offset += 1;
                    return Some(elem);
                }
                None => self.current_offset += 1
            }
        }

        None
    }
}

impl<'a, T> Iterator for SlabMutIter<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<&'a mut T> {
        unsafe { mem::transmute(self.iter.next()) }
    }
}

impl<'a, T> IntoIterator for &'a Slab<T> {
    type Item = &'a T;
    type IntoIter = SlabIter<'a, T>;
    fn into_iter(self) -> SlabIter<'a, T> {
        self.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut Slab<T> {
    type Item = &'a mut T;
    type IntoIter = SlabMutIter<'a, T>;
    fn into_iter(self) -> SlabMutIter<'a, T> {
        self.iter_mut()
    }
}

unsafe impl<T: Send> Send for Slab<T> {}
unsafe impl<T: Sync> Sync for Slab<T> {}
<|endoftext|>