<commit_before>// Copyright 2013-2015, 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>

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use ffi as glib_ffi;
use ffi::{gboolean, gpointer};
use translate::{from_glib, from_glib_full, FromGlib, ToGlib, ToGlibPtr};
use libc;

use Source;

/// The id of a source that is returned by `idle_add` and `timeout_add`.
///
/// A value of 0 is a good default as it is never a valid source ID.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct SourceId(u32);

impl ToGlib for SourceId {
    type GlibType = u32;

    #[inline]
    fn to_glib(&self) -> u32 {
        self.0
    }
}

impl FromGlib<u32> for SourceId {
    #[inline]
    fn from_glib(val: u32) -> SourceId {
        SourceId(val)
    }
}

/// Continue calling the closure in the future iterations or drop it.
///
/// This is the return type of `idle_add` and `timeout_add` closures.
///
/// `Continue(true)` keeps the closure assigned, to be rerun when appropriate.
///
/// `Continue(false)` disconnects and drops it.
pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

/// Unwinding propagation guard. Aborts the process if destroyed while
/// panicking.
pub struct CallbackGuard(());

impl CallbackGuard {
    pub fn new() -> CallbackGuard {
        CallbackGuard(())
    }
}

impl Default for CallbackGuard {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for CallbackGuard {
    fn drop(&mut self) {
        use std::io::stderr;
        use std::io::Write;

        if thread::panicking() {
            let _ = stderr().write(b"Uncaught panic, exiting");
            process::abort();
        }
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    let _guard = CallbackGuard::new();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    let _guard = CallbackGuard::new();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline_child_watch(pid: u32, status: i32, func: gpointer) {
    let _guard = CallbackGuard::new();
    let func: &RefCell<Box<FnMut(u32, i32) + 'static>> = transmute(func);
    (&mut *func.borrow_mut())(pid, status)
}

unsafe extern "C" fn destroy_closure_child_watch(ptr: gpointer) {
    let _guard = CallbackGuard::new();
    Box::<RefCell<Box<FnMut(u32, i32) + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw_child_watch<F: FnMut(u32, i32) + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut(u32, i32) + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn idle_add<F>(func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
/// process exits.
///
/// `func` will be called when `pid` exits
pub fn child_watch_add<'a, N: Into<Option<&'a str>>, F>(pid: u32, func: F) -> SourceId
where F: FnMut(u32, i32) + Send + 'static {
    unsafe {
        let trampoline = trampoline_child_watch as *mut libc::c_void;
        from_glib(glib_ffi::g_child_watch_add_full(glib_ffi::G_PRIORITY_DEFAULT, pid as i32,
            Some(transmute(trampoline)), into_raw_child_watch(func), Some(destroy_closure_child_watch)))
    }
}

#[cfg(unix)]
/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
///
/// `func` will be called repeatedly every time `signum` is raised until it
/// returns `Continue(false)`.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn unix_signal_add<F>(signum: i32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_unix_signal_add_full(glib_ffi::G_PRIORITY_DEFAULT, signum,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Removes the source with the given id `source_id` from the default main context.
///
/// It is a programmer error to attempt to remove a non-existent source.
/// Note: source id are reused.
///
/// For historical reasons, the native function always returns true, so we
/// ignore it here.
pub fn source_remove(source_id: SourceId) {
    unsafe {
        glib_ffi::g_source_remove(source_id.to_glib());
    }
}

/// The priority of sources
///
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Priority(i32);

impl ToGlib for Priority {
    type GlibType = i32;

    #[inline]
    fn to_glib(&self) -> i32 {
        self.0
    }
}

impl FromGlib<i32> for Priority {
    #[inline]
    fn from_glib(val: i32) -> Priority {
        Priority(val)
    }
}

pub const PRIORITY_HIGH: Priority = Priority(glib_ffi::G_PRIORITY_HIGH);
pub const PRIORITY_DEFAULT: Priority = Priority(glib_ffi::G_PRIORITY_DEFAULT);
pub const PRIORITY_HIGH_IDLE: Priority = Priority(glib_ffi::G_PRIORITY_HIGH_IDLE);
pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(glib_ffi::G_PRIORITY_DEFAULT_IDLE);
pub const PRIORITY_LOW: Priority = Priority(glib_ffi::G_PRIORITY_LOW);

/// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
pub fn idle_source_new<'a, N: Into<Option<&'a str>>, F>(name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_idle_source_new();
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
/// intervals with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
pub fn timeout_source_new<'a, N: Into<Option<&'a str>>, F>(interval: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_timeout_source_new(interval);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
/// intervals with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
pub fn timeout_source_new_seconds<'a, N: Into<Option<&'a str>>, F>(interval: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_timeout_source_new_seconds(interval);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
/// process exits.
///
/// `func` will be called when `pid` exits
pub fn child_watch_source_new<'a, N: Into<Option<&'a str>>, F>(pid: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut(u32, i32) + Send + 'static {
    unsafe {
        let source = glib_ffi::g_child_watch_source_new(pid as glib_ffi::GPid);
        let trampoline = trampoline_child_watch as *mut libc::c_void;
        glib_ffi::g_source_set_callback(source, Some(transmute(trampoline)), into_raw_child_watch(func), Some(destroy_closure_child_watch));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

#[cfg(unix)]
/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
/// UNIX signal is raised.
///
/// `func` will be called repeatedly every time `signum` is raised until it
/// returns `Continue(false)`.
pub fn unix_signal_source_new<'a, N: Into<Option<&'a str>>, F>(signum: i32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_unix_signal_source_new(signum);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}
<commit_msg>Add missing backline<commit_after>// Copyright 2013-2015, 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>

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use ffi as glib_ffi;
use ffi::{gboolean, gpointer};
use translate::{from_glib, from_glib_full, FromGlib, ToGlib, ToGlibPtr};
use libc;

use Source;

/// The id of a source that is returned by `idle_add` and `timeout_add`.
///
/// A value of 0 is a good default as it is never a valid source ID.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct SourceId(u32);

impl ToGlib for SourceId {
    type GlibType = u32;

    #[inline]
    fn to_glib(&self) -> u32 {
        self.0
    }
}

impl FromGlib<u32> for SourceId {
    #[inline]
    fn from_glib(val: u32) -> SourceId {
        SourceId(val)
    }
}

/// Continue calling the closure in the future iterations or drop it.
///
/// This is the return type of `idle_add` and `timeout_add` closures.
///
/// `Continue(true)` keeps the closure assigned, to be rerun when appropriate.
///
/// `Continue(false)` disconnects and drops it.
pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

/// Unwinding propagation guard. Aborts the process if destroyed while
/// panicking.
pub struct CallbackGuard(());

impl CallbackGuard {
    pub fn new() -> CallbackGuard {
        CallbackGuard(())
    }
}

impl Default for CallbackGuard {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for CallbackGuard {
    fn drop(&mut self) {
        use std::io::stderr;
        use std::io::Write;

        if thread::panicking() {
            let _ = stderr().write(b"Uncaught panic, exiting\n");
            process::abort();
        }
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    let _guard = CallbackGuard::new();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    let _guard = CallbackGuard::new();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
unsafe extern "C" fn trampoline_child_watch(pid: u32, status: i32, func: gpointer) {
    let _guard = CallbackGuard::new();
    let func: &RefCell<Box<FnMut(u32, i32) + 'static>> = transmute(func);
    (&mut *func.borrow_mut())(pid, status)
}

unsafe extern "C" fn destroy_closure_child_watch(ptr: gpointer) {
    let _guard = CallbackGuard::new();
    Box::<RefCell<Box<FnMut(u32, i32) + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw_child_watch<F: FnMut(u32, i32) + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut(u32, i32) + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn idle_add<F>(func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
/// process exits.
///
/// `func` will be called when `pid` exits
pub fn child_watch_add<'a, N: Into<Option<&'a str>>, F>(pid: u32, func: F) -> SourceId
where F: FnMut(u32, i32) + Send + 'static {
    unsafe {
        let trampoline = trampoline_child_watch as *mut libc::c_void;
        from_glib(glib_ffi::g_child_watch_add_full(glib_ffi::G_PRIORITY_DEFAULT, pid as i32,
            Some(transmute(trampoline)), into_raw_child_watch(func), Some(destroy_closure_child_watch)))
    }
}

#[cfg(unix)]
/// Adds a closure to be called by the default main loop whenever a UNIX signal is raised.
///
/// `func` will be called repeatedly every time `signum` is raised until it
/// returns `Continue(false)`.
///
/// The default main loop almost always is the main loop of the main thread.
/// Thus the closure is called on the main thread.
pub fn unix_signal_add<F>(signum: i32, func: F) -> SourceId
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        from_glib(glib_ffi::g_unix_signal_add_full(glib_ffi::G_PRIORITY_DEFAULT, signum,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

/// Removes the source with the given id `source_id` from the default main context.
///
/// It is a programmer error to attempt to remove a non-existent source.
/// Note: source id are reused.
///
/// For historical reasons, the native function always returns true, so we
/// ignore it here.
pub fn source_remove(source_id: SourceId) {
    unsafe {
        glib_ffi::g_source_remove(source_id.to_glib());
    }
}

/// The priority of sources
///
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Priority(i32);

impl ToGlib for Priority {
    type GlibType = i32;

    #[inline]
    fn to_glib(&self) -> i32 {
        self.0
    }
}

impl FromGlib<i32> for Priority {
    #[inline]
    fn from_glib(val: i32) -> Priority {
        Priority(val)
    }
}

pub const PRIORITY_HIGH: Priority = Priority(glib_ffi::G_PRIORITY_HIGH);
pub const PRIORITY_DEFAULT: Priority = Priority(glib_ffi::G_PRIORITY_DEFAULT);
pub const PRIORITY_HIGH_IDLE: Priority = Priority(glib_ffi::G_PRIORITY_HIGH_IDLE);
pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(glib_ffi::G_PRIORITY_DEFAULT_IDLE);
pub const PRIORITY_LOW: Priority = Priority(glib_ffi::G_PRIORITY_LOW);

/// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
pub fn idle_source_new<'a, N: Into<Option<&'a str>>, F>(name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_idle_source_new();
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
/// intervals with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
pub fn timeout_source_new<'a, N: Into<Option<&'a str>>, F>(interval: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_timeout_source_new(interval);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to at regular
/// intervals with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
pub fn timeout_source_new_seconds<'a, N: Into<Option<&'a str>>, F>(interval: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_timeout_source_new_seconds(interval);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

/// Adds a closure to be called by the main loop the returned `Source` is attached to when a child
/// process exits.
///
/// `func` will be called when `pid` exits
pub fn child_watch_source_new<'a, N: Into<Option<&'a str>>, F>(pid: u32, name: N, priority: Priority, func: F) -> Source
where F: FnMut(u32, i32) + Send + 'static {
    unsafe {
        let source = glib_ffi::g_child_watch_source_new(pid as glib_ffi::GPid);
        let trampoline = trampoline_child_watch as *mut libc::c_void;
        glib_ffi::g_source_set_callback(source, Some(transmute(trampoline)), into_raw_child_watch(func), Some(destroy_closure_child_watch));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}

#[cfg(unix)]
/// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a
/// UNIX signal is raised.
///
/// `func` will be called repeatedly every time `signum` is raised until it
/// returns `Continue(false)`.
pub fn unix_signal_source_new<'a, N: Into<Option<&'a str>>, F>(signum: i32, name: N, priority: Priority, func: F) -> Source
where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        let source = glib_ffi::g_unix_signal_source_new(signum);
        glib_ffi::g_source_set_callback(source, Some(trampoline), into_raw(func), Some(destroy_closure));
        glib_ffi::g_source_set_priority(source, priority.to_glib());

        let name = name.into();
        if let Some(name) = name {
            glib_ffi::g_source_set_name(source, name.to_glib_none().0);
        }

        from_glib_full(source)
    }
}
<|endoftext|>


<commit_before>//! Read and write Elasto Mania replay files.
use std::io::{ Read };
use std::fs::File;
use byteorder::{ ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number to signify end of replay file.
const EOR: i32 = 0x00492F75;

/// One frame of replay.
#[derive(Debug, Default, PartialEq)]
pub struct Frame {
    /// Bike position.
    pub bike: Position<f32>,
    /// Left wheel position.
    pub left_wheel: Position<i16>,
    /// Right wheel position.
    pub right_wheel: Position<i16>,
    /// Head position.
    pub head: Position<i16>,
    /// Bike rotation. Range 0..10000.
    pub rotation: i16,
    /// Left wheel rotation. Range 0..255.
    pub left_wheel_rotation: u8,
    /// Right wheel rotation. Range 0..255.
    pub right_wheel_rotation: u8,
    /// Throttle.
    pub throttle: bool,
    /// Right direction. True = right, False = left.
    // TODO: consider making right field = direction and enum with right and left?
    pub right: bool,
    /// Spring sound effect volume.
    pub volume: i16
}

impl Frame {
    /// Returns a new Frame struct with zero-filled values.
    ///
    /// # Examples
    ///
    /// ```
    /// let frame = elma::rec::Frame::new();
    /// ```
    pub fn new() -> Self {
        Frame {
            bike: Position { x: 0_f32, y: 0_f32 },
            left_wheel: Position { x: 0, y: 0 },
            right_wheel: Position { x: 0, y: 0 },
            head: Position { x: 0, y: 0 },
            rotation: 0,
            left_wheel_rotation: 0,
            right_wheel_rotation: 0,
            throttle: false,
            right: false,
            volume: 0
        }
    }
}

#[derive(Debug, Default, PartialEq)]
/// Replay events.
pub struct Event {
    /// Time of event.
    pub time: f64,
    /// Event type.
    pub event_type: EventType
}

#[derive(Debug, PartialEq)]
/// Type of event.
pub enum EventType {
    /// Apple or flower touch, with index of object.
    Touch { index: i16 },
    Turn,
    VoltRight,
    VoltLeft,
    /// Ground touch, for sound effects. Two types; if alternative is true, uses the second type.
    Ground { alternative: bool }
}

impl Default for EventType {
    fn default() -> EventType { EventType::Touch { index: 0 } }
}

impl Event {
    pub fn new() -> Self {
        Event {
            time: 0_f64,
            event_type: EventType::default()
        }
    }
}

/// Replay struct
#[derive(Debug, PartialEq)]
pub struct Replay {
    /// Raw binary data.
    pub raw: Vec<u8>,
    /// Whether replay is multi-player or not.
    pub multi: bool,
    /// Whether replay is flag-tag or not.
    pub flag_tag: bool,
    /// Random number to link with level file.
    pub link: u32,
    /// Full level filename.
    pub level: String,
    /// Player one frames.
    pub frames: Vec<Frame>,
    /// Player one events.
    pub events: Vec<Event>,
    /// Player two frames.
    pub frames_2: Vec<Frame>,
    /// Player two events.
    pub events_2: Vec<Event>
}

impl Default for Replay {
    fn default() -> Replay { Replay::new() }
}

impl Replay {
    /// Return a new Replay struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let rec = elma::rec::Replay::new();
    /// ```
    pub fn new() -> Self {
        Replay {
            raw: vec![],
            multi: false,
            flag_tag: false,
            link: 0,
            level: String::new(),
            frames: vec![],
            events: vec![],
            frames_2: vec![],
            events_2: vec![]
        }
    }

    /// Loads a replay file and returns a Replay struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let rec = elma::rec::Replay::load("tests/test_1.rec");
    /// ```
    pub fn load(filename: &str) -> Self {
        let mut replay = Replay::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        replay.raw = buffer;
        replay.parse_replay();
        replay
    }

    /// Parses the raw binary data into Replay struct fields.
    fn parse_replay(&mut self) {
        let mut remaining = self.raw.as_slice();

        // TODO: read bytes 8-12 first to see if multi-player replay, then parse it twice.

        // Frame count.
        let frame_count = remaining.read_i32::<LittleEndian>().unwrap();

        // Some unused value, always 0x83.
        let (_, mut remaining) = remaining.split_at(4);

        // Multi-player replay.
        self.multi = remaining.read_i32::<LittleEndian>().unwrap() > 0;

        // Flag-tag replay.
        self.flag_tag = remaining.read_i32::<LittleEndian>().unwrap() > 0;

        // Level link.
        self.link = remaining.read_u32::<LittleEndian>().unwrap();

        // Level file name, including extension.
        let (level, remaining) = remaining.split_at(12);
        self.level = trim_string(level).unwrap();

        // Unknown, unused.
        let (_, remaining) = remaining.split_at(4);

        // Frames.
        self.frames = parse_frames(remaining, frame_count);
        let (_, mut remaining) = remaining.split_at(27*frame_count as usize);

        // Events.
        let event_count = remaining.read_i32::<LittleEndian>().unwrap();
        for n in 0..event_count {
            // Event time
            let time = remaining.read_f64::<LittleEndian>().unwrap();

            // Event details
            let info = remaining.read_i16::<LittleEndian>().unwrap();
            let event = remaining.read_u8().unwrap();
            // Unknown values
            let _ = remaining.read_u8().unwrap();
            let _ = remaining.read_f32::<LittleEndian>().unwrap();
            let event_type = match event {
                0 => EventType::Touch { index: info },
                1 => EventType::Ground { alternative: false },
                5 => EventType::Turn,
                4 => EventType::Ground { alternative: true },
                6 => EventType::VoltRight,
                7 => EventType::VoltLeft,
                _ => panic!("Unknown event type: {:?}\nin event number: {:?}", event, n)
            };

            self.events.push(Event {
                time: time,
                event_type: event_type
            });
        }

        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOR { panic!("EOR marker mismatch: x0{:x} != x0{:x}", expected, EOR); }

        // TODO: Add multi-player replay parsing.
    }

    /// Save replay as a file.
    pub fn save (&self, _filename: &str) {
        unimplemented!();
    }
}

fn parse_frames (frame_data: &[u8], frame_count: i32) -> Vec<Frame> {
    let mut frames: Vec<Frame> = vec![];

    let (mut bike_x, remaining) = frame_data.split_at((frame_count*4) as usize);
    let (mut bike_y, remaining) = remaining.split_at((frame_count*4) as usize);
    let (mut left_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut left_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut right_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut right_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut head_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut head_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut rotation, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut left_rotation, remaining) = remaining.split_at((frame_count) as usize);
    let (mut right_rotation, remaining) = remaining.split_at((frame_count) as usize);
    let (mut data, remaining) = remaining.split_at((frame_count) as usize);
    let (mut volume, _) = remaining.split_at((frame_count*2) as usize);

    for _ in 0..frame_count {
        // Bike X and Y.
        let x = bike_x.read_f32::<LittleEndian>().unwrap();
        let y = bike_y.read_f32::<LittleEndian>().unwrap();
        let bike = Position { x: x, y: y };

        // Left wheel X and Y.
        let x = left_x.read_i16::<LittleEndian>().unwrap();
        let y = left_y.read_i16::<LittleEndian>().unwrap();
        let left_wheel = Position { x: x, y: y };

        // Left wheel X and Y.
        let x = right_x.read_i16::<LittleEndian>().unwrap();
        let y = right_y.read_i16::<LittleEndian>().unwrap();
        let right_wheel = Position { x: x, y: y };

        // Head X and Y.
        let x = head_x.read_i16::<LittleEndian>().unwrap();
        let y = head_y.read_i16::<LittleEndian>().unwrap();
        let head = Position { x: x, y: y };

        // Rotations.
        let rotation = rotation.read_i16::<LittleEndian>().unwrap();
        let left_wheel_rotation = left_rotation.read_u8().unwrap();
        let right_wheel_rotation = right_rotation.read_u8().unwrap();

        // Throttle and turn right.
        let data = data.read_u8().unwrap();
        let throttle = data & 1 != 0;
        let right = data & (1 << 1) != 0;

        // Sound effect volume.
        let volume = volume.read_i16::<LittleEndian>().unwrap();

        frames.push(Frame {
            bike: bike,
            left_wheel: left_wheel,
            right_wheel: right_wheel,
            head: head,
            rotation: rotation,
            left_wheel_rotation: left_wheel_rotation,
            right_wheel_rotation: right_wheel_rotation,
            throttle: throttle,
            right: right,
            volume: volume
        });
    }

    frames
}
<commit_msg>Make event parsing into a function<commit_after>//! Read and write Elasto Mania replay files.
use std::io::{ Read };
use std::fs::File;
use byteorder::{ ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number to signify end of replay file.
const EOR: i32 = 0x00492F75;

/// One frame of replay.
#[derive(Debug, Default, PartialEq)]
pub struct Frame {
    /// Bike position.
    pub bike: Position<f32>,
    /// Left wheel position.
    pub left_wheel: Position<i16>,
    /// Right wheel position.
    pub right_wheel: Position<i16>,
    /// Head position.
    pub head: Position<i16>,
    /// Bike rotation. Range 0..10000.
    pub rotation: i16,
    /// Left wheel rotation. Range 0..255.
    pub left_wheel_rotation: u8,
    /// Right wheel rotation. Range 0..255.
    pub right_wheel_rotation: u8,
    /// Throttle.
    pub throttle: bool,
    /// Right direction. True = right, False = left.
    // TODO: consider making right field = direction and enum with right and left?
    pub right: bool,
    /// Spring sound effect volume.
    pub volume: i16
}

impl Frame {
    /// Returns a new Frame struct with zero-filled values.
    ///
    /// # Examples
    ///
    /// ```
    /// let frame = elma::rec::Frame::new();
    /// ```
    pub fn new() -> Self {
        Frame {
            bike: Position { x: 0_f32, y: 0_f32 },
            left_wheel: Position { x: 0, y: 0 },
            right_wheel: Position { x: 0, y: 0 },
            head: Position { x: 0, y: 0 },
            rotation: 0,
            left_wheel_rotation: 0,
            right_wheel_rotation: 0,
            throttle: false,
            right: false,
            volume: 0
        }
    }
}

#[derive(Debug, Default, PartialEq)]
/// Replay events.
pub struct Event {
    /// Time of event.
    pub time: f64,
    /// Event type.
    pub event_type: EventType
}

#[derive(Debug, PartialEq)]
/// Type of event.
pub enum EventType {
    /// Apple or flower touch, with index of object.
    Touch { index: i16 },
    Turn,
    VoltRight,
    VoltLeft,
    /// Ground touch, for sound effects. Two types; if alternative is true, uses the second type.
    Ground { alternative: bool }
}

impl Default for EventType {
    fn default() -> EventType { EventType::Touch { index: 0 } }
}

impl Event {
    pub fn new() -> Self {
        Event {
            time: 0_f64,
            event_type: EventType::default()
        }
    }
}

/// Replay struct
#[derive(Debug, PartialEq)]
pub struct Replay {
    /// Raw binary data.
    pub raw: Vec<u8>,
    /// Whether replay is multi-player or not.
    pub multi: bool,
    /// Whether replay is flag-tag or not.
    pub flag_tag: bool,
    /// Random number to link with level file.
    pub link: u32,
    /// Full level filename.
    pub level: String,
    /// Player one frames.
    pub frames: Vec<Frame>,
    /// Player one events.
    pub events: Vec<Event>,
    /// Player two frames.
    pub frames_2: Vec<Frame>,
    /// Player two events.
    pub events_2: Vec<Event>
}

impl Default for Replay {
    fn default() -> Replay { Replay::new() }
}

impl Replay {
    /// Return a new Replay struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let rec = elma::rec::Replay::new();
    /// ```
    pub fn new() -> Self {
        Replay {
            raw: vec![],
            multi: false,
            flag_tag: false,
            link: 0,
            level: String::new(),
            frames: vec![],
            events: vec![],
            frames_2: vec![],
            events_2: vec![]
        }
    }

    /// Loads a replay file and returns a Replay struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let rec = elma::rec::Replay::load("tests/test_1.rec");
    /// ```
    pub fn load(filename: &str) -> Self {
        let mut replay = Replay::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        replay.raw = buffer;
        replay.parse_replay();
        replay
    }

    /// Parses the raw binary data into Replay struct fields.
    fn parse_replay(&mut self) {
        let mut remaining = self.raw.as_slice();

        // TODO: read bytes 8-12 first to see if multi-player replay, then parse it twice.

        // Frame count.
        let frame_count = remaining.read_i32::<LittleEndian>().unwrap();
        // Some unused value, always 0x83.
        let (_, mut remaining) = remaining.split_at(4);
        // Multi-player replay.
        self.multi = remaining.read_i32::<LittleEndian>().unwrap() > 0;
        // Flag-tag replay.
        self.flag_tag = remaining.read_i32::<LittleEndian>().unwrap() > 0;
        // Level link.
        self.link = remaining.read_u32::<LittleEndian>().unwrap();
        // Level file name, including extension.
        let (level, remaining) = remaining.split_at(12);
        self.level = trim_string(level).unwrap();
        // Unknown, unused.
        let (_, remaining) = remaining.split_at(4);
        // Frames.
        self.frames = parse_frames(remaining, frame_count);
        let (_, mut remaining) = remaining.split_at(27*frame_count as usize);
        // Events.
        let event_count = remaining.read_i32::<LittleEndian>().unwrap();
        self.events = parse_events(remaining, event_count);
        let (_, mut remaining) = remaining.split_at(16*event_count as usize);
        // End of replay marker.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOR { panic!("EOR marker mismatch: x0{:x} != x0{:x}", expected, EOR); }

        // TODO: Add multi-player replay parsing.
    }

    /// Save replay as a file.
    pub fn save (&self, _filename: &str) {
        unimplemented!();
    }
}

/// Function for parsing frame data from either single-player or multi-player replays.
fn parse_frames (frame_data: &[u8], frame_count: i32) -> Vec<Frame> {
    let mut frames: Vec<Frame> = vec![];

    let (mut bike_x, remaining) = frame_data.split_at((frame_count*4) as usize);
    let (mut bike_y, remaining) = remaining.split_at((frame_count*4) as usize);
    let (mut left_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut left_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut right_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut right_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut head_x, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut head_y, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut rotation, remaining) = remaining.split_at((frame_count*2) as usize);
    let (mut left_rotation, remaining) = remaining.split_at((frame_count) as usize);
    let (mut right_rotation, remaining) = remaining.split_at((frame_count) as usize);
    let (mut data, remaining) = remaining.split_at((frame_count) as usize);
    let (mut volume, _) = remaining.split_at((frame_count*2) as usize);

    for _ in 0..frame_count {
        // Bike X and Y.
        let x = bike_x.read_f32::<LittleEndian>().unwrap();
        let y = bike_y.read_f32::<LittleEndian>().unwrap();
        let bike = Position { x: x, y: y };
        // Left wheel X and Y.
        let x = left_x.read_i16::<LittleEndian>().unwrap();
        let y = left_y.read_i16::<LittleEndian>().unwrap();
        let left_wheel = Position { x: x, y: y };
        // Left wheel X and Y.
        let x = right_x.read_i16::<LittleEndian>().unwrap();
        let y = right_y.read_i16::<LittleEndian>().unwrap();
        let right_wheel = Position { x: x, y: y };
        // Head X and Y.
        let x = head_x.read_i16::<LittleEndian>().unwrap();
        let y = head_y.read_i16::<LittleEndian>().unwrap();
        let head = Position { x: x, y: y };
        // Rotations.
        let rotation = rotation.read_i16::<LittleEndian>().unwrap();
        let left_wheel_rotation = left_rotation.read_u8().unwrap();
        let right_wheel_rotation = right_rotation.read_u8().unwrap();
        // Throttle and turn right.
        let data = data.read_u8().unwrap();
        let throttle = data & 1 != 0;
        let right = data & (1 << 1) != 0;
        // Sound effect volume.
        let volume = volume.read_i16::<LittleEndian>().unwrap();

        frames.push(Frame {
            bike: bike,
            left_wheel: left_wheel,
            right_wheel: right_wheel,
            head: head,
            rotation: rotation,
            left_wheel_rotation: left_wheel_rotation,
            right_wheel_rotation: right_wheel_rotation,
            throttle: throttle,
            right: right,
            volume: volume
        });
    }

    frames
}

/// Function for parsing event data from either single-player or multi-player replays.
fn parse_events (mut event_data: &[u8], event_count: i32) -> Vec<Event> {
    let mut events: Vec<Event> = vec![];

    for n in 0..event_count {
        // Event time
        let time = event_data.read_f64::<LittleEndian>().unwrap();
        // Event details
        let info = event_data.read_i16::<LittleEndian>().unwrap();
        let event = event_data.read_u8().unwrap();
        // Unknown values
        let _ = event_data.read_u8().unwrap();
        let _ = event_data.read_f32::<LittleEndian>().unwrap();
        let event_type = match event {
            0 => EventType::Touch { index: info },
            1 => EventType::Ground { alternative: false },
            5 => EventType::Turn,
            4 => EventType::Ground { alternative: true },
            6 => EventType::VoltRight,
            7 => EventType::VoltLeft,
            _ => panic!("Unknown event type: {:?}\nin event number: {:?}", event, n)
        };

        events.push(Event {
            time: time,
            event_type: event_type
        });
    }

    events
}
<|endoftext|>


<commit_before>use serde_json;

use line::Line;

pub struct Update {
    pub lines: Vec<Line>,
    height: u64,
    pub scroll_to: (u64, u64),
    pub first_line: u64
}

impl Update {
    pub fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let scroll_to = object.get("scrollto").unwrap().as_array().unwrap();
        let mut lines: Vec<Line> = vec![];
        for line in object.get("lines").unwrap().as_array().unwrap().iter() {
            lines.push(Line::from_value(line));
        }
        Update {
            height: object.get("height").unwrap().as_u64().unwrap(),
            first_line: object.get("first_line").unwrap().as_u64().unwrap(),
            lines: lines,
            scroll_to: (scroll_to[0].as_u64().unwrap(), scroll_to[1].as_u64().unwrap()),
        }
    }
}
<commit_msg>Changes parsing for Update to match current protocol<commit_after>use serde_json;

use op::Op;

pub struct Update {
    rev: u64,
    ops: Vec<Op>,
}

impl Update {
    pub fn from_value(value: &serde_json::Value) -> Update {
        let object = value.as_object().unwrap();
        let ops = object.get("ops").unwrap().as_array().unwrap().iter().map(
            |op| Op::from_value(op)
        ).collect();
        Update {
            rev: object.get("rev").unwrap().as_u64().unwrap(),
            ops: ops,
        }
    }
}
<|endoftext|>


<commit_before>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
    pub description: String,
    pub is_official: bool,
    pub is_trusted: bool,
    pub name: String,
    pub star_count: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
    pub Created: u64,
    pub Id: String,
    pub ParentId: String,
    pub Labels: Option<HashMap<String, String>>,
    pub RepoTags: Vec<String>,
    pub RepoDigests: Option<Vec<String>>,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
    pub Architecture: String,
    pub Author: String,
    pub Comment: String,
    pub Config: Config,
    pub Created: String,
    pub DockerVersion: String,
    pub Id: String,
    pub Os: String,
    pub Parent: String,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
    pub Created: u64,
    pub Command: String,
    pub Id: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    pub Names: Vec<String>,
    pub Ports: Vec<Port>,
    pub Status: String,
    pub SizeRw: Option<u64>,
    pub SizeRootFs: Option<u64>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
    pub AppArmorProfile: String,
    pub Args: Vec<String>,
    pub Config: Config,
    pub Created: String,
    pub Driver: String,
    // pub ExecIDs: ??
    pub HostConfig: HostConfig,
    pub HostnamePath: String,
    pub HostsPath: String,
    pub LogPath: String,
    pub Id: String,
    pub Image: String,
    pub MountLabel: String,
    pub NetworkSettings: NetworkSettings,
    pub Path: String,
    pub ProcessLabel: String,
    pub ResolvConfPath: String,
    pub RestartCount: u64,
    pub State: State,
    pub Mounts: Vec<Mount>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Mount {
    pub Source: String,
    pub Destination: String,
    pub Mode: String,
    pub RW: bool,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct State {
    pub Error: String,
    pub ExitCode: u64,
    pub FinishedAt: String,
    pub OOMKilled: bool,
    pub Paused: bool,
    pub Pid: u64,
    pub Restarting: bool,
    pub Running: bool,
    pub StartedAt: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct NetworkSettings {
    pub Bridge: String,
    pub Gateway: String,
    pub IPAddress: String,
    pub IPPrefixLen: u64,
    pub MacAddress: String, /*    pub PortMapping: Option<???>,
                             *   pub Ports: Option<???> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
    pub CgroupParent: Option<String>,
    pub ContainerIDFile: String,
    pub CpuShares: Option<u64>,
    pub CpusetCpus: Option<String>,
    pub Memory: Option<u64>,
    pub MemorySwap: Option<u64>,
    pub NetworkMode: String,
    pub PidMode: Option<String>,
    // pub PortBindings: ???
    pub Privileged: bool,
    pub PublishAllPorts: bool,
    pub ReadonlyRootfs: Option<bool>, /* pub RestartPolicy: ???
                                       * pub SecurityOpt: Option<???>,
                                       * pub Ulimits: Option<???>
                                       * pub VolumesFrom: Option<??/> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
    pub AttachStderr: bool,
    pub AttachStdin: bool,
    pub AttachStdout: bool,
    pub Cmd: Option<Vec<String>>,
    pub Domainname: String,
    pub Entrypoint: Option<Vec<String>>,
    pub Env: Option<Vec<String>>,
    // ExposedPorts
    pub Hostname: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    // pub MacAddress: String,
    pub OnBuild: Option<String>,
    // pub NetworkDisabled: bool,
    pub OpenStdin: bool,
    pub StdinOnce: bool,
    pub Tty: bool,
    pub User: String,
    pub WorkingDir: String,
}

impl Config {
    pub fn env(&self) -> HashMap<String, String> {
        let mut map = HashMap::new();
        match self.Env {
            Some(ref vars) => {
                for e in vars {
                    let pair: Vec<&str> = e.split("=").collect();
                    map.insert(pair[0].to_owned(), pair[1].to_owned());
                }
            }
            _ => (),
        };
        map
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
    pub IP: Option<String>,
    pub PrivatePort: u64,
    pub PublicPort: Option<u64>,
    pub Type: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
    pub read: String,
    pub networks: HashMap<String, Network>,
    pub memory_stats: MemoryStats,
    pub blkio_stats: BlkioStats,
    pub cpu_stats: CpuStats,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
    pub rx_dropped: u64,
    pub rx_bytes: u64,
    pub rx_errors: u64,
    pub tx_packets: u64,
    pub tx_dropped: u64,
    pub rx_packets: u64,
    pub tx_errors: u64,
    pub tx_bytes: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
    pub max_usage: u64,
    pub usage: u64,
    pub failcnt: u64,
    pub limit: u64,
    pub stats: MemoryStat,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
    pub total_pgmajfault: u64,
    pub cache: u64,
    pub mapped_file: u64,
    pub total_inactive_file: u64,
    pub pgpgout: u64,
    pub rss: u64,
    pub total_mapped_file: u64,
    pub writeback: u64,
    pub unevictable: u64,
    pub pgpgin: u64,
    pub total_unevictable: u64,
    pub pgmajfault: u64,
    pub total_rss: u64,
    pub total_rss_huge: u64,
    pub total_writeback: u64,
    pub total_inactive_anon: u64,
    pub rss_huge: u64,
    pub hierarchical_memory_limit: u64,
    pub hierarchical_memsw_limit: u64,
    pub total_pgfault: u64,
    pub total_active_file: u64,
    pub active_anon: u64,
    pub total_active_anon: u64,
    pub total_pgpgout: u64,
    pub total_cache: u64,
    pub inactive_anon: u64,
    pub active_file: u64,
    pub pgfault: u64,
    pub inactive_file: u64,
    pub total_pgpgin: u64,
    pub swap: u64,
    pub total_swap: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
    pub cpu_usage: CpuUsage,
    pub system_cpu_usage: u64,
    pub throttling_data: ThrottlingData,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
    pub percpu_usage: Vec<u64>,
    pub usage_in_usermode: u64,
    pub total_usage: u64,
    pub usage_in_kernelmode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
    pub periods: u64,
    pub throttled_periods: u64,
    pub throttled_time: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
    pub io_service_bytes_recursive: Vec<BlkioStat>,
    pub io_serviced_recursive: Vec<BlkioStat>,
    pub io_queue_recursive: Vec<BlkioStat>,
    pub io_service_time_recursive: Vec<BlkioStat>,
    pub io_wait_time_recursive: Vec<BlkioStat>,
    pub io_merged_recursive: Vec<BlkioStat>,
    pub io_time_recursive: Vec<BlkioStat>,
    pub sectors_recursive: Vec<BlkioStat>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
    pub major: u64,
    pub minor: u64,
    pub op: String,
    pub value: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
    pub Kind: u64,
    pub Path: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
    pub Titles: Vec<String>,
    pub Processes: Vec<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
    pub ApiVersion: String,
    pub Version: String,
    pub GitCommit: String,
    pub GoVersion: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
    pub Containers: u64,
    pub Images: u64,
    pub Driver: String,
    pub DockerRootDir: String,
    pub DriverStatus: Vec<Vec<String>>,
    pub ExecutionDriver: String,
    pub ID: String,
    pub KernelVersion: String,
    // pub Labels: Option<???>,
    pub MemTotal: u64,
    pub MemoryLimit: bool,
    pub NCPU: u64,
    pub NEventsListener: u64,
    pub NGoroutines: u64,
    pub Name: String,
    pub OperatingSystem: String,
    // pub RegistryConfig:???
    pub SwapLimit: bool,
    pub SystemTime: Option<String>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
    pub Id: String,
    pub Warnings: Option<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
    pub Id: String,
    pub Created: u64,
    pub CreatedBy: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
    pub StatusCode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Event {
    pub status: String,
    pub id: String,
    pub from: Option<String>,
    pub time: u64,
    pub timeNano: u64,
}

#[derive(Debug)]
pub enum BuildOutput {
    Stream(String),
    Err(String),
}

// fixme: all fields are options because PullInfo.progressDefault is sometimes an empty object instead of a null/absent value
#[derive(Clone, Debug, RustcDecodable)]
pub struct ProgressDetail {
    current: Option<u64>,
    total: Option<u64>,
    status: Option<String>, // fixme: it looks like this field isn't deserializing properly
}

#[derive(Clone, Debug, RustcDecodable)]
#[allow(non_snake_case)]
pub struct PullInfo {
    pub id: Option<String>,
    pub status: String,
    pub progress: Option<String>,
    pub progressDetail: Option<ProgressDetail>,
}

#[derive(Debug)]
pub enum PullOutput {
    Status {
        id: Option<String>,
        status: String,
        progress: Option<String>,
        progress_detail: Option<ProgressDetail>,
    },
    Err(String),
}

#[derive(Debug)]
pub enum Status {
    Untagged(String),
    Deleted(String),
}
<commit_msg>Make id and status optional for events<commit_after>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
    pub description: String,
    pub is_official: bool,
    pub is_trusted: bool,
    pub name: String,
    pub star_count: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
    pub Created: u64,
    pub Id: String,
    pub ParentId: String,
    pub Labels: Option<HashMap<String, String>>,
    pub RepoTags: Vec<String>,
    pub RepoDigests: Option<Vec<String>>,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
    pub Architecture: String,
    pub Author: String,
    pub Comment: String,
    pub Config: Config,
    pub Created: String,
    pub DockerVersion: String,
    pub Id: String,
    pub Os: String,
    pub Parent: String,
    pub Size: u64,
    pub VirtualSize: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
    pub Created: u64,
    pub Command: String,
    pub Id: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    pub Names: Vec<String>,
    pub Ports: Vec<Port>,
    pub Status: String,
    pub SizeRw: Option<u64>,
    pub SizeRootFs: Option<u64>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
    pub AppArmorProfile: String,
    pub Args: Vec<String>,
    pub Config: Config,
    pub Created: String,
    pub Driver: String,
    // pub ExecIDs: ??
    pub HostConfig: HostConfig,
    pub HostnamePath: String,
    pub HostsPath: String,
    pub LogPath: String,
    pub Id: String,
    pub Image: String,
    pub MountLabel: String,
    pub NetworkSettings: NetworkSettings,
    pub Path: String,
    pub ProcessLabel: String,
    pub ResolvConfPath: String,
    pub RestartCount: u64,
    pub State: State,
    pub Mounts: Vec<Mount>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Mount {
    pub Source: String,
    pub Destination: String,
    pub Mode: String,
    pub RW: bool,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct State {
    pub Error: String,
    pub ExitCode: u64,
    pub FinishedAt: String,
    pub OOMKilled: bool,
    pub Paused: bool,
    pub Pid: u64,
    pub Restarting: bool,
    pub Running: bool,
    pub StartedAt: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct NetworkSettings {
    pub Bridge: String,
    pub Gateway: String,
    pub IPAddress: String,
    pub IPPrefixLen: u64,
    pub MacAddress: String, /*    pub PortMapping: Option<???>,
                             *   pub Ports: Option<???> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
    pub CgroupParent: Option<String>,
    pub ContainerIDFile: String,
    pub CpuShares: Option<u64>,
    pub CpusetCpus: Option<String>,
    pub Memory: Option<u64>,
    pub MemorySwap: Option<u64>,
    pub NetworkMode: String,
    pub PidMode: Option<String>,
    // pub PortBindings: ???
    pub Privileged: bool,
    pub PublishAllPorts: bool,
    pub ReadonlyRootfs: Option<bool>, /* pub RestartPolicy: ???
                                       * pub SecurityOpt: Option<???>,
                                       * pub Ulimits: Option<???>
                                       * pub VolumesFrom: Option<??/> */
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
    pub AttachStderr: bool,
    pub AttachStdin: bool,
    pub AttachStdout: bool,
    pub Cmd: Option<Vec<String>>,
    pub Domainname: String,
    pub Entrypoint: Option<Vec<String>>,
    pub Env: Option<Vec<String>>,
    // ExposedPorts
    pub Hostname: String,
    pub Image: String,
    pub Labels: HashMap<String, String>,
    // pub MacAddress: String,
    pub OnBuild: Option<String>,
    // pub NetworkDisabled: bool,
    pub OpenStdin: bool,
    pub StdinOnce: bool,
    pub Tty: bool,
    pub User: String,
    pub WorkingDir: String,
}

impl Config {
    pub fn env(&self) -> HashMap<String, String> {
        let mut map = HashMap::new();
        match self.Env {
            Some(ref vars) => {
                for e in vars {
                    let pair: Vec<&str> = e.split("=").collect();
                    map.insert(pair[0].to_owned(), pair[1].to_owned());
                }
            }
            _ => (),
        };
        map
    }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
    pub IP: Option<String>,
    pub PrivatePort: u64,
    pub PublicPort: Option<u64>,
    pub Type: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
    pub read: String,
    pub networks: HashMap<String, Network>,
    pub memory_stats: MemoryStats,
    pub blkio_stats: BlkioStats,
    pub cpu_stats: CpuStats,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
    pub rx_dropped: u64,
    pub rx_bytes: u64,
    pub rx_errors: u64,
    pub tx_packets: u64,
    pub tx_dropped: u64,
    pub rx_packets: u64,
    pub tx_errors: u64,
    pub tx_bytes: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
    pub max_usage: u64,
    pub usage: u64,
    pub failcnt: u64,
    pub limit: u64,
    pub stats: MemoryStat,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
    pub total_pgmajfault: u64,
    pub cache: u64,
    pub mapped_file: u64,
    pub total_inactive_file: u64,
    pub pgpgout: u64,
    pub rss: u64,
    pub total_mapped_file: u64,
    pub writeback: u64,
    pub unevictable: u64,
    pub pgpgin: u64,
    pub total_unevictable: u64,
    pub pgmajfault: u64,
    pub total_rss: u64,
    pub total_rss_huge: u64,
    pub total_writeback: u64,
    pub total_inactive_anon: u64,
    pub rss_huge: u64,
    pub hierarchical_memory_limit: u64,
    pub hierarchical_memsw_limit: u64,
    pub total_pgfault: u64,
    pub total_active_file: u64,
    pub active_anon: u64,
    pub total_active_anon: u64,
    pub total_pgpgout: u64,
    pub total_cache: u64,
    pub inactive_anon: u64,
    pub active_file: u64,
    pub pgfault: u64,
    pub inactive_file: u64,
    pub total_pgpgin: u64,
    pub swap: u64,
    pub total_swap: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
    pub cpu_usage: CpuUsage,
    pub system_cpu_usage: u64,
    pub throttling_data: ThrottlingData,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
    pub percpu_usage: Vec<u64>,
    pub usage_in_usermode: u64,
    pub total_usage: u64,
    pub usage_in_kernelmode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
    pub periods: u64,
    pub throttled_periods: u64,
    pub throttled_time: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
    pub io_service_bytes_recursive: Vec<BlkioStat>,
    pub io_serviced_recursive: Vec<BlkioStat>,
    pub io_queue_recursive: Vec<BlkioStat>,
    pub io_service_time_recursive: Vec<BlkioStat>,
    pub io_wait_time_recursive: Vec<BlkioStat>,
    pub io_merged_recursive: Vec<BlkioStat>,
    pub io_time_recursive: Vec<BlkioStat>,
    pub sectors_recursive: Vec<BlkioStat>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
    pub major: u64,
    pub minor: u64,
    pub op: String,
    pub value: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
    pub Kind: u64,
    pub Path: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
    pub Titles: Vec<String>,
    pub Processes: Vec<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
    pub ApiVersion: String,
    pub Version: String,
    pub GitCommit: String,
    pub GoVersion: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
    pub Containers: u64,
    pub Images: u64,
    pub Driver: String,
    pub DockerRootDir: String,
    pub DriverStatus: Vec<Vec<String>>,
    pub ExecutionDriver: String,
    pub ID: String,
    pub KernelVersion: String,
    // pub Labels: Option<???>,
    pub MemTotal: u64,
    pub MemoryLimit: bool,
    pub NCPU: u64,
    pub NEventsListener: u64,
    pub NGoroutines: u64,
    pub Name: String,
    pub OperatingSystem: String,
    // pub RegistryConfig:???
    pub SwapLimit: bool,
    pub SystemTime: Option<String>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
    pub Id: String,
    pub Warnings: Option<Vec<String>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
    pub Id: String,
    pub Created: u64,
    pub CreatedBy: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
    pub StatusCode: u64,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Event {
    pub status: Option<String>,
    pub id: Option<String>,
    pub from: Option<String>,
    pub time: u64,
    pub timeNano: u64,
}

#[derive(Debug)]
pub enum BuildOutput {
    Stream(String),
    Err(String),
}

// fixme: all fields are options because PullInfo.progressDefault is sometimes an empty object instead of a null/absent value
#[derive(Clone, Debug, RustcDecodable)]
pub struct ProgressDetail {
    current: Option<u64>,
    total: Option<u64>,
    status: Option<String>, // fixme: it looks like this field isn't deserializing properly
}

#[derive(Clone, Debug, RustcDecodable)]
#[allow(non_snake_case)]
pub struct PullInfo {
    pub id: Option<String>,
    pub status: String,
    pub progress: Option<String>,
    pub progressDetail: Option<ProgressDetail>,
}

#[derive(Debug)]
pub enum PullOutput {
    Status {
        id: Option<String>,
        status: String,
        progress: Option<String>,
        progress_detail: Option<ProgressDetail>,
    },
    Err(String),
}

#[derive(Debug)]
pub enum Status {
    Untagged(String),
    Deleted(String),
}
<|endoftext|>


<commit_before>//! This module contains definition of table rows stuff
use std::io::{Write, Error};
use std::iter::FromIterator;
use std::slice::{Iter, IterMut};
use std::ops::{Index, IndexMut};

use term::Terminal;

use super::utils::NEWLINE;
use super::cell::Cell;
use super::format::{TableFormat, ColumnPosition};

/// Represent a table row made of cells
#[derive(Clone, Debug)]
pub struct Row {
	cells: Vec<Cell>
}

impl Row {
	/// Create a new `Row` backed with `cells` vector
	pub fn new(cells: Vec<Cell>) -> Row {
		Row {
			cells: cells
		}
	}

	/// Create an row of length `size`, with empty strings stored
	pub fn empty() -> Row {
		Self::new(vec![Cell::default(); 0])
	}

	/// Get the number of cells in this row
	pub fn len(&self) -> usize {
		self.cells.len()
	}

	/// Get the height of this row
	pub fn get_height(&self) -> usize {
		let mut height = 1; // Minimum height must be 1 to print empty rows
		for cell in &self.cells {
			let h = cell.get_height();
			if h > height {
				height = h;
			}
		}
		height
	}

	/// Get the minimum width required by the cell in the column `column`.
	/// Return 0 if the cell does not exist in this row
	pub fn get_cell_width(&self, column: usize) -> usize {
		match self.cells.get(column) {
			Some(cell) => cell.get_width(),
			None => 0
		}
	}

	/// Get the cell at index `idx`
	pub fn get_cell(&self, idx: usize) -> Option<&Cell> {
		self.cells.get(idx)
	}

	/// Get the mutable cell at index `idx`
	pub fn get_mut_cell(&mut self, idx: usize) -> Option<&mut Cell> {
		self.cells.get_mut(idx)
	}

	/// Set the `cell` in the row at the given `column`
	pub fn set_cell(&mut self, cell: Cell, column: usize) -> Result<(), &str> {
		if column >= self.len() {
			return Err("Cannot find cell");
		}
		self.cells[column] = cell;
		Ok(())
	}

	/// Append a `cell` at the end of the row
	pub fn add_cell(&mut self, cell: Cell) {
		self.cells.push(cell);
	}

	/// Insert `cell` at position `index`. If `index` is higher than the row lenght,
	/// the cell will be appended at the end
	pub fn insert_cell(&mut self, index: usize, cell: Cell) {
		if index < self.cells.len() {
			self.cells.insert(index, cell);
		} else {
			self.add_cell(cell);
		}
	}

	/// Remove the cell at position `index`. Silently skip if this cell does not exist
	pub fn remove_cell(&mut self, index: usize) {
		if index < self.cells.len() {
			self.cells.remove(index);
		}
	}

    /// Returns an immutable iterator over cells
    pub fn iter<'a>(&'a self) -> Iter<'a, Cell> {
        self.cells.iter()
    }

	/// Returns an mutable iterator over cells
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Cell> {
        self.cells.iter_mut()
    }

	/// Internal only
	fn __print<T:Write+?Sized, F>(&self, out: &mut T, format: &TableFormat, col_width: &[usize], f: F) -> Result<(), Error>
		where F: Fn(&Cell, &mut T, usize, usize, bool) -> Result<(), Error>
	{
		for i in 0..self.get_height() {
			try!(format.print_column_separator(out, ColumnPosition::Left));
			let (lp, rp) = format.get_padding();
			for j in 0..col_width.len() {
				try!(out.write(&vec![' ' as u8; lp]));
				let skip_r_fill = (j == col_width.len() - 1) && format.get_column_separator(ColumnPosition::Right).is_none();
				match self.get_cell(j) {
					Some(ref c) => try!(f(c, out, i, col_width[j], skip_r_fill)),
					None => try!(f(&Cell::default(), out, i, col_width[j], skip_r_fill))
				};
				try!(out.write(&vec![' ' as u8; rp]));
				if j < col_width.len() - 1 {
					try!(format.print_column_separator(out, ColumnPosition::Intern));
				}
			}
			try!(format.print_column_separator(out, ColumnPosition::Right));
			try!(out.write_all(NEWLINE));
		}
		Ok(())
	}

	/// Print the row to `out`, with `separator` as column separator, and `col_width`
	/// specifying the width of each columns
	pub fn print<T: Write+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
		self.__print(out, format, col_width, Cell::print)
	}

	/// Print the row to terminal `out`, with `separator` as column separator, and `col_width`
	/// specifying the width of each columns. Apply style when needed
	pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
		self.__print(out, format, col_width, Cell::print_term)
	}
}

impl Default for Row {
	fn default() -> Row {
		Row::empty()
	}
}

impl Index<usize> for Row {
	type Output = Cell;
	fn index(&self, idx: usize) -> &Self::Output {
		&self.cells[idx]
	}
}

impl IndexMut<usize> for Row {
	fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
		&mut self.cells[idx]
	}
}

impl <A: ToString> FromIterator<A> for Row {
	fn from_iter<T>(iterator: T) -> Row where T: IntoIterator<Item=A> {
		Self::new(iterator.into_iter().map(|ref e| Cell::from(e)).collect())
	}
}

impl <T, A> From<T> for Row where A: ToString, T : IntoIterator<Item=A> {
	fn from(it: T) -> Row {
		Self::from_iter(it)
	}
}

impl <'a> IntoIterator for &'a Row {
	type Item=&'a Cell;
	type IntoIter=Iter<'a, Cell>;
	fn into_iter(self) -> Self::IntoIter {
		self.iter()
	}
}

impl <'a> IntoIterator for &'a mut Row {
	type Item=&'a mut Cell;
	type IntoIter=IterMut<'a, Cell>;
	fn into_iter(self) -> Self::IntoIter {
		self.iter_mut()
	}
}

/// This macro simplifies `Row` creation
///
/// The syntax support style spec
/// # Example
/// ```
/// # #[macro_use] extern crate prettytable;
/// # fn main() {
/// // Create a normal row
/// let row1 = row!["Element 1", "Element 2", "Element 3"];
/// // Create a row with all cells formatted with red foreground color, yellow background color
/// // bold, italic, align in the center of the cell
/// let row2 = row![FrBybic => "Element 1", "Element 2", "Element 3"];
/// // Create a row with first cell in blue, second one in red, and last one with default style
/// let row3 = row![Fb->"blue", Fr->"red", "normal"];
/// // Do something with rows
/// # drop(row1);
/// # drop(row2);
/// # drop(row3);
/// # }
/// ```
///
/// For details about style specifier syntax, check doc for [Cell::style_spec](cell/struct.Cell.html#method.style_spec) method
#[macro_export]
macro_rules! row {
	(($($out:tt)*); $value:expr) => (vec![$($out)* cell!($value)]);
	(($($out:tt)*); $value:expr, $($n:tt)*) => (row!(($($out)* cell!($value),); $($n)*));
	(($($out:tt)*); $style:ident -> $value:expr) => (vec![$($out)* cell!($style -> $value)]);
	(($($out:tt)*); $style:ident -> $value:expr, $($n: tt)*) => (row!(($($out)* cell!($style -> $value),); $($n)*));

	($($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($content)), *]));
	($style:ident => $($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($style -> $content)), *]));
	($($content:tt)*) => ($crate::row::Row::new(row!((); $($content)*)));
}
<commit_msg>Replace match with mapping<commit_after>//! This module contains definition of table rows stuff
use std::io::{Write, Error};
use std::iter::FromIterator;
use std::slice::{Iter, IterMut};
use std::ops::{Index, IndexMut};

use term::Terminal;

use super::utils::NEWLINE;
use super::cell::Cell;
use super::format::{TableFormat, ColumnPosition};

/// Represent a table row made of cells
#[derive(Clone, Debug)]
pub struct Row {
	cells: Vec<Cell>
}

impl Row {
	/// Create a new `Row` backed with `cells` vector
	pub fn new(cells: Vec<Cell>) -> Row {
		Row {
			cells: cells
		}
	}

	/// Create an row of length `size`, with empty strings stored
	pub fn empty() -> Row {
		Self::new(vec![Cell::default(); 0])
	}

	/// Get the number of cells in this row
	pub fn len(&self) -> usize {
		self.cells.len()
	}

	/// Get the height of this row
	pub fn get_height(&self) -> usize {
		let mut height = 1; // Minimum height must be 1 to print empty rows
		for cell in &self.cells {
			let h = cell.get_height();
			if h > height {
				height = h;
			}
		}
		height
	}

	/// Get the minimum width required by the cell in the column `column`.
	/// Return 0 if the cell does not exist in this row
	pub fn get_cell_width(&self, column: usize) -> usize {
		self.cells.get(column).map(|cell| cell.get_width()).unwrap_or(0)
	}

	/// Get the cell at index `idx`
	pub fn get_cell(&self, idx: usize) -> Option<&Cell> {
		self.cells.get(idx)
	}

	/// Get the mutable cell at index `idx`
	pub fn get_mut_cell(&mut self, idx: usize) -> Option<&mut Cell> {
		self.cells.get_mut(idx)
	}

	/// Set the `cell` in the row at the given `column`
	pub fn set_cell(&mut self, cell: Cell, column: usize) -> Result<(), &str> {
		if column >= self.len() {
			return Err("Cannot find cell");
		}
		self.cells[column] = cell;
		Ok(())
	}

	/// Append a `cell` at the end of the row
	pub fn add_cell(&mut self, cell: Cell) {
		self.cells.push(cell);
	}

	/// Insert `cell` at position `index`. If `index` is higher than the row lenght,
	/// the cell will be appended at the end
	pub fn insert_cell(&mut self, index: usize, cell: Cell) {
		if index < self.cells.len() {
			self.cells.insert(index, cell);
		} else {
			self.add_cell(cell);
		}
	}

	/// Remove the cell at position `index`. Silently skip if this cell does not exist
	pub fn remove_cell(&mut self, index: usize) {
		if index < self.cells.len() {
			self.cells.remove(index);
		}
	}

    /// Returns an immutable iterator over cells
    pub fn iter<'a>(&'a self) -> Iter<'a, Cell> {
        self.cells.iter()
    }

	/// Returns an mutable iterator over cells
    pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, Cell> {
        self.cells.iter_mut()
    }

	/// Internal only
	fn __print<T:Write+?Sized, F>(&self, out: &mut T, format: &TableFormat, col_width: &[usize], f: F) -> Result<(), Error>
		where F: Fn(&Cell, &mut T, usize, usize, bool) -> Result<(), Error>
	{
		for i in 0..self.get_height() {
			try!(format.print_column_separator(out, ColumnPosition::Left));
			let (lp, rp) = format.get_padding();
			for j in 0..col_width.len() {
				try!(out.write(&vec![' ' as u8; lp]));
				let skip_r_fill = (j == col_width.len() - 1) && format.get_column_separator(ColumnPosition::Right).is_none();
				match self.get_cell(j) {
					Some(ref c) => try!(f(c, out, i, col_width[j], skip_r_fill)),
					None => try!(f(&Cell::default(), out, i, col_width[j], skip_r_fill))
				};
				try!(out.write(&vec![' ' as u8; rp]));
				if j < col_width.len() - 1 {
					try!(format.print_column_separator(out, ColumnPosition::Intern));
				}
			}
			try!(format.print_column_separator(out, ColumnPosition::Right));
			try!(out.write_all(NEWLINE));
		}
		Ok(())
	}

	/// Print the row to `out`, with `separator` as column separator, and `col_width`
	/// specifying the width of each columns
	pub fn print<T: Write+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
		self.__print(out, format, col_width, Cell::print)
	}

	/// Print the row to terminal `out`, with `separator` as column separator, and `col_width`
	/// specifying the width of each columns. Apply style when needed
	pub fn print_term<T: Terminal+?Sized>(&self, out: &mut T, format: &TableFormat, col_width: &[usize]) -> Result<(), Error> {
		self.__print(out, format, col_width, Cell::print_term)
	}
}

impl Default for Row {
	fn default() -> Row {
		Row::empty()
	}
}

impl Index<usize> for Row {
	type Output = Cell;
	fn index(&self, idx: usize) -> &Self::Output {
		&self.cells[idx]
	}
}

impl IndexMut<usize> for Row {
	fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
		&mut self.cells[idx]
	}
}

impl <A: ToString> FromIterator<A> for Row {
	fn from_iter<T>(iterator: T) -> Row where T: IntoIterator<Item=A> {
		Self::new(iterator.into_iter().map(|ref e| Cell::from(e)).collect())
	}
}

impl <T, A> From<T> for Row where A: ToString, T : IntoIterator<Item=A> {
	fn from(it: T) -> Row {
		Self::from_iter(it)
	}
}

impl <'a> IntoIterator for &'a Row {
	type Item=&'a Cell;
	type IntoIter=Iter<'a, Cell>;
	fn into_iter(self) -> Self::IntoIter {
		self.iter()
	}
}

impl <'a> IntoIterator for &'a mut Row {
	type Item=&'a mut Cell;
	type IntoIter=IterMut<'a, Cell>;
	fn into_iter(self) -> Self::IntoIter {
		self.iter_mut()
	}
}

/// This macro simplifies `Row` creation
///
/// The syntax support style spec
/// # Example
/// ```
/// # #[macro_use] extern crate prettytable;
/// # fn main() {
/// // Create a normal row
/// let row1 = row!["Element 1", "Element 2", "Element 3"];
/// // Create a row with all cells formatted with red foreground color, yellow background color
/// // bold, italic, align in the center of the cell
/// let row2 = row![FrBybic => "Element 1", "Element 2", "Element 3"];
/// // Create a row with first cell in blue, second one in red, and last one with default style
/// let row3 = row![Fb->"blue", Fr->"red", "normal"];
/// // Do something with rows
/// # drop(row1);
/// # drop(row2);
/// # drop(row3);
/// # }
/// ```
///
/// For details about style specifier syntax, check doc for [Cell::style_spec](cell/struct.Cell.html#method.style_spec) method
#[macro_export]
macro_rules! row {
	(($($out:tt)*); $value:expr) => (vec![$($out)* cell!($value)]);
	(($($out:tt)*); $value:expr, $($n:tt)*) => (row!(($($out)* cell!($value),); $($n)*));
	(($($out:tt)*); $style:ident -> $value:expr) => (vec![$($out)* cell!($style -> $value)]);
	(($($out:tt)*); $style:ident -> $value:expr, $($n: tt)*) => (row!(($($out)* cell!($style -> $value),); $($n)*));

	($($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($content)), *]));
	($style:ident => $($content:expr), *) => ($crate::row::Row::new(vec![$(cell!($style -> $content)), *]));
	($($content:tt)*) => ($crate::row::Row::new(row!((); $($content)*)));
}
<|endoftext|>