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

//! GdkDisplay — Controls a set of GdkScreens and their associated input devices

use ffi;
use glib::translate::*;
use glib::types::{StaticType, Type};
use atom::Atom;
use app_launch_context::AppLaunchContext;
use device::Device;
use device_manager::DeviceManager;
use object::Object;
use screen::Screen;
use window::Window;

pub type Display = Object<ffi::GdkDisplay>;

impl StaticType for Display {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_display_get_type()) } }
}

impl Display {
    pub fn open(display_name: &str) -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_open(display_name.to_glib_none().0)) }
    }

    pub fn get_default() -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_get_default()) }
    }

    pub fn get_name(&self) -> String {
        unsafe { from_glib_none(ffi::gdk_display_get_name(self.to_glib_none().0)) }
    }

    pub fn get_screen(&self, screen_num: i32) -> Screen {
        unsafe { from_glib_none(ffi::gdk_display_get_screen(self.to_glib_none().0, screen_num)) }
    }

    pub fn get_default_screen(&self) -> Screen {
        unsafe {
            from_glib_none(ffi::gdk_display_get_default_screen(self.to_glib_none().0))
        }
    }

    pub fn get_device_manager(&self) -> Option<DeviceManager> {
        unsafe { from_glib_none(ffi::gdk_display_get_device_manager(self.to_glib_none().0)) }
    }

    pub fn device_is_grabbed(&self, device: &Device) -> bool {
        unsafe {
            from_glib(ffi::gdk_display_device_is_grabbed(self.to_glib_none().0,
                      device.to_glib_none().0))
        }
    }

    pub fn beep(&self) {
        unsafe { ffi::gdk_display_beep(self.to_glib_none().0) }
    }

    pub fn sync(&self) {
        unsafe { ffi::gdk_display_sync(self.to_glib_none().0) }
    }

    pub fn flush(&self) {
        unsafe { ffi::gdk_display_flush(self.to_glib_none().0) }
    }

    pub fn close(&self) {
        unsafe { ffi::gdk_display_close(self.to_glib_none().0) }
    }

    pub fn is_closed(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_is_closed(self.to_glib_none().0)) }
    }

    /*pub fn get_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_get_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn peek_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_peek_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn put_event(&self, event: &::Event) {
        unsafe { ffi::gdk_display_put_event(self.to_glib_none().0, event.to_glib_none().0 as *const ffi::GdkEvent) }
    }*/

    pub fn has_pending(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_has_pending(self.to_glib_none().0)) }
    }

    pub fn set_double_click_time(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_time(self.to_glib_none().0, msec) }
    }

    pub fn set_double_click_distance(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_distance(self.to_glib_none().0, msec) }
    }

    pub fn supports_cursor_color(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_color(self.to_glib_none().0)) }
    }

    pub fn supports_cursor_alpha(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_alpha(self.to_glib_none().0)) }
    }

    pub fn get_default_cursor_size(&self) -> u32 {
        unsafe { ffi::gdk_display_get_default_cursor_size(self.to_glib_none().0) }
    }

    pub fn get_maximal_cursor_size(&self, width: &mut u32, height: &mut u32) {
        unsafe { ffi::gdk_display_get_maximal_cursor_size(self.to_glib_none().0, width, height) }
    }

    pub fn get_default_group(&self) -> Window {
        unsafe { from_glib_none(ffi::gdk_display_get_default_group(self.to_glib_none().0)) }
    }

    pub fn supports_selection_notification(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_selection_notification(self.to_glib_none().0)) }
    }

    pub fn request_selection_notification(&self, selection: &Atom) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_display_request_selection_notification(self.to_glib_none().0,
                    selection.to_glib_none().0))
        }
    }

    pub fn supports_clipboard_persistence(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_clipboard_persistence(self.to_glib_none().0)) }
    }

    /*pub fn store_clipboard(&self, clipboard_window: &::Window, time_: u32, targets: Vec<Atom>) {
        unsafe { ffi::gdk_display_store_clipboard(self.to_glib_none().0, clipboard_window.to_glib_none().0, time_, targets.as_mut_pointer(),
            targets.len() as c_int) }
    }*/

    pub fn supports_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_shapes(self.to_glib_none().0)) }
    }

    pub fn supports_input_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_input_shapes(self.to_glib_none().0)) }
    }

    pub fn supports_composite(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_composite(self.to_glib_none().0)) }
    }

    pub fn get_app_launch_context(&self) -> AppLaunchContext {
        unsafe { from_glib_full(ffi::gdk_display_get_app_launch_context(self.to_glib_none().0)) }
    }

    pub fn notify_startup_complete(&self, startup_id: &str) {
        unsafe {
            ffi::gdk_display_notify_startup_complete(self.to_glib_none().0,
                                                     startup_id.to_glib_none().0)
        }
    }
}
<commit_msg>Add Display documentation<commit_after>// Copyright 2013-2015, The Rust-GNOME 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>

//! Display — Controls a set of GdkScreens and their associated input devices
//!
//! #Description
//!
//! Display objects purpose are two fold:
//! * To manage and provide information about input devices (pointers and keyboards)
//! * To manage and provide information about the available Screens
//!
//! Display objects are the GDK representation of an X Display, which can be described as
//! a workstation consisting of a keyboard, a pointing device (such as a mouse) and one or
//! more screens. It is used to open and keep track of various GdkScreen objects currently
//! instantiated by the application. It is also used to access the keyboard(s) and mouse
//! pointer(s) of the display.
//!
//! Most of the input device handling has been factored out into the separate DeviceManager
//! object. Every display has a device manager, which you can obtain using
//! Display::get_device_manager().

use ffi;
use glib::translate::*;
use glib::types::{StaticType, Type};
use atom::Atom;
use app_launch_context::AppLaunchContext;
use device::Device;
use device_manager::DeviceManager;
use object::Object;
use screen::Screen;
use window::Window;

pub type Display = Object<ffi::GdkDisplay>;

impl StaticType for Display {
    fn static_type() -> Type { unsafe { from_glib(ffi::gdk_display_get_type()) } }
}

impl Display {
    /// Opens a display.
    pub fn open(display_name: &str) -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_open(display_name.to_glib_none().0)) }
    }

    /// Gets the default Display. This is a convenience function for:
    /// DisplayManager::get_default_display(DisplayManager::get()).
    pub fn get_default() -> Option<Display> {
        unsafe { from_glib_none(ffi::gdk_display_get_default()) }
    }

    /// Gets the name of the display.
    pub fn get_name(&self) -> String {
        unsafe { from_glib_none(ffi::gdk_display_get_name(self.to_glib_none().0)) }
    }

    /// Returns a screen object for one of the screens of the display.
    pub fn get_screen(&self, screen_num: i32) -> Screen {
        unsafe { from_glib_none(ffi::gdk_display_get_screen(self.to_glib_none().0, screen_num)) }
    }

    /// Get the default Screen for `self`.
    pub fn get_default_screen(&self) -> Screen {
        unsafe {
            from_glib_none(ffi::gdk_display_get_default_screen(self.to_glib_none().0))
        }
    }

    /// Returns the DeviceManager associated to `self`.
    pub fn get_device_manager(&self) -> Option<DeviceManager> {
        unsafe { from_glib_none(ffi::gdk_display_get_device_manager(self.to_glib_none().0)) }
    }

    /// Returns true if there is an ongoing grab on `device` for `self`.
    pub fn device_is_grabbed(&self, device: &Device) -> bool {
        unsafe {
            from_glib(ffi::gdk_display_device_is_grabbed(self.to_glib_none().0,
                      device.to_glib_none().0))
        }
    }

    /// Emits a short beep on `self`.
    pub fn beep(&self) {
        unsafe { ffi::gdk_display_beep(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system and waits until all requests
    /// have been handled. This is often used for making sure that the display is synchronized
    /// with the current state of the program. Calling Display::sync() before
    /// gdk::error_trap_pop() makes sure that any errors generated from earlier requests are
    /// handled before the error trap is removed.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled
    /// synchronously, this function will do nothing.
    pub fn sync(&self) {
        unsafe { ffi::gdk_display_sync(self.to_glib_none().0) }
    }

    /// Flushes any requests queued for the windowing system; this happens automatically when
    /// the main loop blocks waiting for new events, but if your application is drawing without
    /// returning control to the main loop, you may need to call this function explicitly. A
    /// common case where this function needs to be called is when an application is executing
    /// drawing commands from a thread other than the thread where the main loop is running.
    ///
    /// This is most useful for X11. On windowing systems where requests are handled synchronously,
    /// this function will do nothing.
    pub fn flush(&self) {
        unsafe { ffi::gdk_display_flush(self.to_glib_none().0) }
    }

    /// Closes the connection to the windowing system for the given display, and cleans up
    /// associated resources.
    pub fn close(&self) {
        unsafe { ffi::gdk_display_close(self.to_glib_none().0) }
    }

    /// Finds out if the display has been closed.
    pub fn is_closed(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_is_closed(self.to_glib_none().0)) }
    }

    /*pub fn get_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_get_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn peek_event(&self) -> Option<::Event> {
        unsafe { ffi::gdk_display_peek_event(self.to_glib_none().0) };

        if tmp.is_null() {
            None
        } else {
            unsafe { Some(::Event::wrap(tmp)) }
        }
    }

    pub fn put_event(&self, event: &::Event) {
        unsafe { ffi::gdk_display_put_event(self.to_glib_none().0, event.to_glib_none().0 as *const ffi::GdkEvent) }
    }*/

    /// Returns whether the display has events that are waiting to be processed.
    pub fn has_pending(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_has_pending(self.to_glib_none().0)) }
    }

    /// Sets the double click time (two clicks within this time interval count as a double click
    /// and result in a GDK_2BUTTON_PRESS event). Applications should not set this, it is a global
    /// user-configured setting.
    pub fn set_double_click_time(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_time(self.to_glib_none().0, msec) }
    }

    /// Sets the double click distance (two clicks within this distance count as a double click and
    /// result in a GDK_2BUTTON_PRESS event). See also Display::set_double_click_time(). Applications
    /// should not set this, it is a global user-configured setting.
    pub fn set_double_click_distance(&self, msec: u32) {
        unsafe { ffi::gdk_display_set_double_click_distance(self.to_glib_none().0, msec) }
    }

    /// Returns true if multicolored cursors are supported on `self`. Otherwise, cursors have only a
    /// foerground and a background color.
    pub fn supports_cursor_color(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_color(self.to_glib_none().0)) }
    }

    /// Returns true if cursors can use an 8bit alpha channel on `self`. Otherwise, cursors are
    /// restricted to bilevel alpha (i.e. a mask).
    pub fn supports_cursor_alpha(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_cursor_alpha(self.to_glib_none().0)) }
    }

    /// Returns the default size to use for cursors on `self`.
    pub fn get_default_cursor_size(&self) -> u32 {
        unsafe { ffi::gdk_display_get_default_cursor_size(self.to_glib_none().0) }
    }

    /// Gets the maximal size to use for cursors on `self`.
    pub fn get_maximal_cursor_size(&self, width: &mut u32, height: &mut u32) {
        unsafe { ffi::gdk_display_get_maximal_cursor_size(self.to_glib_none().0, width, height) }
    }

    /// Returns the default group leader window for all toplevel windows on `self`. This
    /// window is implicitly created by GDK. See Window::set_group().
    pub fn get_default_group(&self) -> Window {
        unsafe { from_glib_none(ffi::gdk_display_get_default_group(self.to_glib_none().0)) }
    }

    /// Returns whether GdkEventOwnerChange events will be sent when the owner of a selection
    /// changes.
    pub fn supports_selection_notification(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_selection_notification(self.to_glib_none().0)) }
    }

    /// Request GdkEventOwnerChange events for ownership changes of the selection named by the
    /// given atom.
    pub fn request_selection_notification(&self, selection: &Atom) -> bool {
        unsafe {
            from_glib(
                ffi::gdk_display_request_selection_notification(self.to_glib_none().0,
                    selection.to_glib_none().0))
        }
    }

    /// Returns whether the speicifed display supports clipboard persistance; i.e. if it’s
    /// possible to store the clipboard data after an application has quit. On X11 this checks
    /// if a clipboard daemon is running.
    pub fn supports_clipboard_persistence(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_clipboard_persistence(self.to_glib_none().0)) }
    }

    /*pub fn store_clipboard(&self, clipboard_window: &::Window, time_: u32, targets: Vec<Atom>) {
        unsafe { ffi::gdk_display_store_clipboard(self.to_glib_none().0, clipboard_window.to_glib_none().0, time_, targets.as_mut_pointer(),
            targets.len() as c_int) }
    }*/

    /// Returns true if Window::shape_combine_mask() can be used to create shaped windows on
    /// `self`.
    pub fn supports_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::input_shape_combine_mask() can be used to modify the input shape
    /// of windows on `self`.
    pub fn supports_input_shapes(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_input_shapes(self.to_glib_none().0)) }
    }

    /// Returns true if Window::set_composited() can be used to redirect drawing on the window
    /// using compositing.
    ///
    /// Currently this only works on X11 with XComposite and XDamage extensions available.
    ///
    /// Deprecated since GDK 3.16
    #[cfg(not(feature = "gdk_3_16"))]
    pub fn supports_composite(&self) -> bool {
        unsafe { from_glib(ffi::gdk_display_supports_composite(self.to_glib_none().0)) }
    }

    /// Returns an AppLaunchContext suitable for launching applications on the given display.
    pub fn get_app_launch_context(&self) -> AppLaunchContext {
        unsafe { from_glib_full(ffi::gdk_display_get_app_launch_context(self.to_glib_none().0)) }
    }

    /// Indicates to the GUI environment that the application has finished loading, using a
    /// given identifier.
    ///
    /// GTK+ will call this function automatically for GtkWindow with custom startup-notification
    /// identifier unless gtk::Window::set_auto_startup_notification() is called to disable that
    /// feature.
    pub fn notify_startup_complete(&self, startup_id: &str) {
        unsafe {
            ffi::gdk_display_notify_startup_complete(self.to_glib_none().0,
                                                     startup_id.to_glib_none().0)
        }
    }
}
<|endoftext|>


<commit_before>// The size of an ELF header tag, in bytes. This was calculated
// from reading the ELF format specification.
const ELF_SECTION_HEADER_SIZE: u64 = 64;

#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionTag {
    tag_type: u32,
    size: u32,
    num: u16,
    entsize: u16,
    shndx: u16,
    reserved: u16,
    first_section: ElfSectionHeader
}

impl ElfSectionTag {
    pub fn elf_sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            section_index: 0,
            total_sections: self.num as u32,
            entry_size: self.entsize as u64
        }
    }

    pub fn section_count(&self) -> usize {
        self.num as usize
    }

    pub fn size(&self) -> usize {
        self.size as usize
    }

    pub fn entry_size(&self) -> usize {
        self.entsize as usize
    }
}

#[derive(Debug)]
#[repr(C)]
pub struct ElfSectionHeader {
    sh_name: u32,
    sh_type: u32,
    sh_flags: u64,
    sh_addr: u64,
    sh_offset: u64,
    sh_size: u64,
    sh_link: u32,
    sh_info: u32,
    sh_addralign: u64,
    sh_entsize: u64
}

impl ElfSectionHeader {
    pub fn section_type(&self) -> usize {
        self.sh_type as usize
    }

    pub fn section_start_address(&self) -> usize {
        self.sh_addr as usize
    }

    pub fn section_end_address(&self) -> usize {
        (self.sh_addr + self.sh_size) as usize
    }

    pub fn size(&self) -> usize {
        self.sh_size as usize
    }

    pub fn flags(&self) -> usize {
        self.sh_flags as usize
    }

    pub fn entry_size(&self) -> usize {
        self.sh_entsize as usize
    }
}

pub struct ElfSectionIter {
    current_section: &'static ElfSectionHeader,
    section_index: u32,
    total_sections: u32,
    entry_size: u64
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSectionHeader;

    fn next(&mut self) -> Option<Self::Item> {
        if self.section_index >= self.total_sections {
            return None;
        } else {
            let section = self.current_section;
            let next_section_addr =
                (self.current_section as *const ElfSectionHeader as u64) + self.entry_size;
            let next_section = unsafe {
                &*(next_section_addr as *const ElfSectionHeader)
            };

            self.current_section = next_section;
            self.section_index += 1;

            Some(section)
        }
    }
}
<commit_msg>Representation adjustments.<commit_after>// The size of an ELF header tag, in bytes. This was calculated
// from reading the ELF format specification.
const ELF_SECTION_HEADER_SIZE: u64 = 64;

#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionTag {
    tag_type: u32,
    size: u32,
    num: u32,
    entsize: u32,
    shndx: u32,
    //reserved: u16,
    first_section: ElfSectionHeader
}

impl ElfSectionTag {
    pub fn elf_sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            section_index: 0,
            total_sections: self.num as u32,
            entry_size: self.entsize as u64
        }
    }

    pub fn section_count(&self) -> usize {
        self.num as usize
    }

    pub fn size(&self) -> usize {
        self.size as usize
    }

    pub fn entry_size(&self) -> usize {
        self.entsize as usize
    }
}

#[derive(Debug)]
#[repr(C)]
pub struct ElfSectionHeader {
    sh_name: u32,
    sh_type: u32,
    sh_flags: u64,
    sh_addr: u64,
    sh_offset: u64,
    sh_size: u64,
    sh_link: u32,
    sh_info: u32,
    sh_addralign: u64,
    sh_entsize: u64
}

impl ElfSectionHeader {
    pub fn section_type(&self) -> usize {
        self.sh_type as usize
    }

    pub fn section_start_address(&self) -> usize {
        self.sh_addr as usize
    }

    pub fn section_end_address(&self) -> usize {
        (self.sh_addr + self.sh_size) as usize
    }

    pub fn size(&self) -> usize {
        self.sh_size as usize
    }

    pub fn flags(&self) -> usize {
        self.sh_flags as usize
    }

    pub fn entry_size(&self) -> usize {
        self.sh_entsize as usize
    }
}

pub struct ElfSectionIter {
    current_section: &'static ElfSectionHeader,
    section_index: u32,
    total_sections: u32,
    entry_size: u64
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSectionHeader;

    fn next(&mut self) -> Option<Self::Item> {
        if self.section_index >= self.total_sections {
            return None;
        } else {
            let section = self.current_section;
            let next_section_addr =
                (self.current_section as *const ElfSectionHeader as u64) + self.entry_size;
            let next_section = unsafe {
                &*(next_section_addr as *const ElfSectionHeader)
            };

            self.current_section = next_section;
            self.section_index += 1;

            Some(section)
        }
    }
}
<|endoftext|>


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

#![allow(dead_code)]

use libc::close;
use libc::dup2;
// FIXME
use libc::getpid;
use std::env;
use std::io;
use std::io::{Error, ErrorKind, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::unix::net::UnixStream;
use std::os::unix::process::CommandExt;
use std::process::{Child, Command};
use unix_socket::os::linux::SocketAddrExt;
use unix_socket::UnixListener as AbstractUnixListener;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixStream as AbstractStream;

pub enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream, Option<Child>),
}

pub fn varlink_exec(address: String) -> io::Result<(Child, String)> {
    let executable = &address[5..];
    let listener = AbstractUnixListener::bind("")?;
    let local_addr = listener.local_addr()?;
    let path = local_addr.as_abstract();
    let fd = listener.into_raw_fd();
    let child = Command::new(executable)
        .arg(format!(
            "--varlink=unix:@{}",
            String::from_utf8_lossy(path.unwrap())
        ))
        .before_exec(move || {
            unsafe {
                if fd != 3 {
                    close(3);
                    dup2(fd, 3);
                }
                env::set_var("LISTEN_FDS", "1");
                env::set_var("LISTEN_FDNAMES", "varlink");
                env::set_var("LISTEN_PID", format!("{}", getpid()));
            }
            Ok(())
        })
        .spawn()?;
    Ok((
        child,
        format!("unix:@{}", String::from_utf8_lossy(path.unwrap())),
    ))
}

impl<'a> VarlinkStream {
    pub fn connect(address: &str) -> io::Result<(Self, String)> {
        let mut address: String = address.into();
        let mut my_child: Option<Child> = None;

        if address.starts_with("exec:") {
            let (c, a) = varlink_exec(address)?;
            address = a;
            my_child = Some(c);
        }

        if address.starts_with("tcp:") {
            Ok((
                VarlinkStream::TCP(TcpStream::connect(&address[4..])?),
                address,
            ))
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(";").next().unwrap());
            if addr.starts_with("@") {
                addr = addr.replacen("@", "\0", 1);
                let l = AbstractStream::connect(addr)?;
                unsafe {
                    return Ok((
                        VarlinkStream::UNIX(UnixStream::from_raw_fd(l.into_raw_fd()), my_child),
                        address,
                    ));
                }
            }
            Ok((
                VarlinkStream::UNIX(UnixStream::connect(addr)?, my_child),
                address,
            ))
        } else {
            Err(Error::new(ErrorKind::Other, "unknown varlink address"))
        }
    }

    pub fn split(&mut self) -> io::Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s, _) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both),
            VarlinkStream::UNIX(ref mut s, _) => s.shutdown(Shutdown::Both),
        }
    }

    pub fn set_nonblocking(&self, b: bool) -> io::Result<()> {
        match self {
            &VarlinkStream::TCP(ref l) => l.set_nonblocking(b),
            &VarlinkStream::UNIX(ref l, _) => l.set_nonblocking(b),
        }
    }
}

impl Drop for VarlinkStream {
    fn drop(&mut self) {
        let _r = self.shutdown();
        match *self {
            VarlinkStream::UNIX(_, Some(ref mut child)) => {
                let _res = child.kill();
                let _res = child.wait();
            }
            _ => {}
        }
    }
}
<commit_msg>use architecture cfg macro for exec:<commit_after>//! Handle network connections for a varlink service

#![allow(dead_code)]

use std::io;
use std::io::{Error, ErrorKind, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::unix::net::UnixStream;
use std::process::Child;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixStream as AbstractStream;

pub enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream, Option<Child>),
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub fn varlink_exec(_address: String) -> io::Result<(Child, String)> {
    unimplemented!();
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn varlink_exec(address: String) -> io::Result<(Child, String)> {
    use unix_socket::os::linux::SocketAddrExt;
    use libc::close;
    use libc::dup2;
    use libc::getpid;
    use std::env;
    use std::os::unix::process::CommandExt;
    use std::process::Command;
    use unix_socket::UnixListener as AbstractUnixListener;

    let executable = &address[5..];
    let listener = AbstractUnixListener::bind("")?;
    let local_addr = listener.local_addr()?;
    let path = local_addr.as_abstract();
    let fd = listener.into_raw_fd();
    let child = Command::new(executable)
        .arg(format!(
            "--varlink=unix:@{}",
            String::from_utf8_lossy(path.unwrap())
        ))
        .before_exec(move || {
            unsafe {
                if fd != 3 {
                    close(3);
                    dup2(fd, 3);
                }
                env::set_var("LISTEN_FDS", "1");
                env::set_var("LISTEN_FDNAMES", "varlink");
                env::set_var("LISTEN_PID", format!("{}", getpid()));
            }
            Ok(())
        })
        .spawn()?;
    Ok((
        child,
        format!("unix:@{}", String::from_utf8_lossy(path.unwrap())),
    ))
}

impl<'a> VarlinkStream {
    pub fn connect(address: &str) -> io::Result<(Self, String)> {
        let mut address: String = address.into();
        let mut my_child: Option<Child> = None;

        if address.starts_with("exec:") {
            let (c, a) = varlink_exec(address)?;
            address = a;
            my_child = Some(c);
        }

        if address.starts_with("tcp:") {
            Ok((
                VarlinkStream::TCP(TcpStream::connect(&address[4..])?),
                address,
            ))
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(";").next().unwrap());
            if addr.starts_with("@") {
                addr = addr.replacen("@", "\0", 1);
                let l = AbstractStream::connect(addr)?;
                unsafe {
                    return Ok((
                        VarlinkStream::UNIX(UnixStream::from_raw_fd(l.into_raw_fd()), my_child),
                        address,
                    ));
                }
            }
            Ok((
                VarlinkStream::UNIX(UnixStream::connect(addr)?, my_child),
                address,
            ))
        } else {
            Err(Error::new(ErrorKind::Other, "unknown varlink address"))
        }
    }

    pub fn split(&mut self) -> io::Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s, _) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both),
            VarlinkStream::UNIX(ref mut s, _) => s.shutdown(Shutdown::Both),
        }
    }

    pub fn set_nonblocking(&self, b: bool) -> io::Result<()> {
        match self {
            &VarlinkStream::TCP(ref l) => l.set_nonblocking(b),
            &VarlinkStream::UNIX(ref l, _) => l.set_nonblocking(b),
        }
    }
}

impl Drop for VarlinkStream {
    fn drop(&mut self) {
        let _r = self.shutdown();
        match *self {
            VarlinkStream::UNIX(_, Some(ref mut child)) => {
                let _res = child.kill();
                let _res = child.wait();
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>//!
//! This module defines a manager for holding multiple instances of mock servers.
//!

use crate::mock_server::MockServer;

use pact_matching::models::Pact;
use std::collections::BTreeMap;

struct ServerEntry {
    mock_server: Box<MockServer>,
    join_handle: tokio::task::JoinHandle<()>,
}

/// Struct to represent many mock servers running in a background thread
pub struct ServerManager {
    runtime: tokio::runtime::Runtime,
    mock_servers: BTreeMap<String, ServerEntry>,
}

impl ServerManager {
    /// Construct a new ServerManager for scheduling several instances of mock servers
    /// on one tokio runtime.
    pub fn new() -> ServerManager {
        ServerManager {
            runtime: tokio::runtime::Builder::new()
                .threaded_scheduler()
                .core_threads(1)
                .enable_all()
                .build()
                .unwrap(),
            mock_servers: BTreeMap::new(),
        }
    }

    /// Start a new server on the runtime
    pub fn start_mock_server_with_addr(
        &mut self,
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr,
    ) -> Result<std::net::SocketAddr, String> {
        let (mock_server, future) =
            self.runtime
                .block_on(MockServer::new(id.clone(), pact, addr))?;

        let addr = mock_server.addr;

        self.mock_servers.insert(
            id,
            ServerEntry {
                mock_server: Box::new(mock_server),
                join_handle: self.runtime.spawn(future),
            },
        );
        Ok(addr)
    }

    /// Start a new server on the runtime
    pub fn start_mock_server(&mut self, id: String, pact: Pact, port: u16) -> Result<u16, String> {
        self.start_mock_server_with_addr(id, pact, ([0, 0, 0, 0], port as u16).into())
            .map(|addr| addr.port())
    }

    /// Shut down a server by its id
    pub fn shutdown_mock_server_by_id(&mut self, id: String) -> bool {
        match self.mock_servers.remove(&id) {
            Some(mut entry) => match entry.mock_server.shutdown() {
                Ok(()) => {
                    self.runtime.block_on(entry.join_handle).unwrap();
                    true
                }
                Err(_) => false,
            },
            None => false,
        }
    }

    /// Shut down a server by its local port number
    pub fn shutdown_mock_server_by_port(&mut self, port: u16) -> bool {
        log::debug!("Shutting down mock server with port {}", port);
        let result = self
            .mock_servers
            .iter()
            .find(|(_id, entry)| entry.mock_server.addr.port() == port)
            .map(|(_id, entry)| entry.mock_server.id.clone());

        if let Some(id) = result {
            if let Some(mut entry) = self.mock_servers.remove(&id) {
                return match entry.mock_server.shutdown() {
                    Ok(()) => {
                        self.runtime.block_on(entry.join_handle).unwrap();
                        true
                    }
                    Err(_) => false,
                };
            }
        }

        false
    }

    /// Find mock server by id, and map it using supplied function if found
    pub fn find_mock_server_by_id<R>(
        &self,
        id: &String,
        f: &dyn Fn(&MockServer) -> R,
    ) -> Option<R> {
        match self.mock_servers.get(id) {
            Some(entry) => Some(f(&entry.mock_server)),
            None => None,
        }
    }

    /// Find a mock server by port number and apply a mutating operation on it if successful
    pub fn find_mock_server_by_port_mut<R>(
        &mut self,
        mock_server_port: u16,
        f: &dyn Fn(&mut MockServer) -> R,
    ) -> Option<R> {
        match self
            .mock_servers
            .iter_mut()
            .find(|(_id, entry)| entry.mock_server.addr.port() == mock_server_port)
        {
            Some((_id, entry)) => Some(f(&mut entry.mock_server)),
            None => None,
        }
    }

    /// Map all the running mock servers
    pub fn map_mock_servers<R>(&self, f: &dyn Fn(&MockServer) -> R) -> Vec<R> {
        let mut results = vec![];
        for (_id_, entry) in self.mock_servers.iter() {
            results.push(f(&entry.mock_server));
        }
        return results;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::TcpStream;
    use std::{thread, time};

    #[test]
    fn manager_should_start_and_shutdown_mock_server() {
        let mut manager = ServerManager::new();
        let start_result = manager.start_mock_server("foobar".into(), Pact::default(), 0);

        assert!(start_result.is_ok());
        let server_port = start_result.unwrap();

        // Server should be up
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_ok());

        // Should be able to read matches without blocking
        let matches =
            manager.find_mock_server_by_port_mut(server_port, &|mock_server| mock_server.matches());
        assert_eq!(matches, Some(vec![]));

        let stopped = manager.shutdown_mock_server_by_port(server_port);
        assert!(stopped);

        // The tokio runtime is now out of tasks
        drop(manager);

        let ten_millis = time::Duration::from_millis(10);
        thread::sleep(ten_millis);

        // Server should be down
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_err());
    }
}
<commit_msg>chore: increase timeout for test on Appveyor<commit_after>//!
//! This module defines a manager for holding multiple instances of mock servers.
//!

use crate::mock_server::MockServer;

use pact_matching::models::Pact;
use std::collections::BTreeMap;

struct ServerEntry {
    mock_server: Box<MockServer>,
    join_handle: tokio::task::JoinHandle<()>,
}

/// Struct to represent many mock servers running in a background thread
pub struct ServerManager {
    runtime: tokio::runtime::Runtime,
    mock_servers: BTreeMap<String, ServerEntry>,
}

impl ServerManager {
    /// Construct a new ServerManager for scheduling several instances of mock servers
    /// on one tokio runtime.
    pub fn new() -> ServerManager {
        ServerManager {
            runtime: tokio::runtime::Builder::new()
                .threaded_scheduler()
                .core_threads(1)
                .enable_all()
                .build()
                .unwrap(),
            mock_servers: BTreeMap::new(),
        }
    }

    /// Start a new server on the runtime
    pub fn start_mock_server_with_addr(
        &mut self,
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr,
    ) -> Result<std::net::SocketAddr, String> {
        let (mock_server, future) =
            self.runtime
                .block_on(MockServer::new(id.clone(), pact, addr))?;

        let addr = mock_server.addr;

        self.mock_servers.insert(
            id,
            ServerEntry {
                mock_server: Box::new(mock_server),
                join_handle: self.runtime.spawn(future),
            },
        );
        Ok(addr)
    }

    /// Start a new server on the runtime
    pub fn start_mock_server(&mut self, id: String, pact: Pact, port: u16) -> Result<u16, String> {
        self.start_mock_server_with_addr(id, pact, ([0, 0, 0, 0], port as u16).into())
            .map(|addr| addr.port())
    }

    /// Shut down a server by its id
    pub fn shutdown_mock_server_by_id(&mut self, id: String) -> bool {
        match self.mock_servers.remove(&id) {
            Some(mut entry) => match entry.mock_server.shutdown() {
                Ok(()) => {
                    self.runtime.block_on(entry.join_handle).unwrap();
                    true
                }
                Err(_) => false,
            },
            None => false,
        }
    }

    /// Shut down a server by its local port number
    pub fn shutdown_mock_server_by_port(&mut self, port: u16) -> bool {
        log::debug!("Shutting down mock server with port {}", port);
        let result = self
            .mock_servers
            .iter()
            .find(|(_id, entry)| entry.mock_server.addr.port() == port)
            .map(|(_id, entry)| entry.mock_server.id.clone());

        if let Some(id) = result {
            if let Some(mut entry) = self.mock_servers.remove(&id) {
                return match entry.mock_server.shutdown() {
                    Ok(()) => {
                        self.runtime.block_on(entry.join_handle).unwrap();
                        true
                    }
                    Err(_) => false,
                };
            }
        }

        false
    }

    /// Find mock server by id, and map it using supplied function if found
    pub fn find_mock_server_by_id<R>(
        &self,
        id: &String,
        f: &dyn Fn(&MockServer) -> R,
    ) -> Option<R> {
        match self.mock_servers.get(id) {
            Some(entry) => Some(f(&entry.mock_server)),
            None => None,
        }
    }

    /// Find a mock server by port number and apply a mutating operation on it if successful
    pub fn find_mock_server_by_port_mut<R>(
        &mut self,
        mock_server_port: u16,
        f: &dyn Fn(&mut MockServer) -> R,
    ) -> Option<R> {
        match self
            .mock_servers
            .iter_mut()
            .find(|(_id, entry)| entry.mock_server.addr.port() == mock_server_port)
        {
            Some((_id, entry)) => Some(f(&mut entry.mock_server)),
            None => None,
        }
    }

    /// Map all the running mock servers
    pub fn map_mock_servers<R>(&self, f: &dyn Fn(&MockServer) -> R) -> Vec<R> {
        let mut results = vec![];
        for (_id_, entry) in self.mock_servers.iter() {
            results.push(f(&entry.mock_server));
        }
        return results;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::TcpStream;
    use std::{thread, time};

    #[test]
    fn manager_should_start_and_shutdown_mock_server() {
        let mut manager = ServerManager::new();
        let start_result = manager.start_mock_server("foobar".into(), Pact::default(), 0);

        assert!(start_result.is_ok());
        let server_port = start_result.unwrap();

        // Server should be up
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_ok());

        // Should be able to read matches without blocking
        let matches =
            manager.find_mock_server_by_port_mut(server_port, &|mock_server| mock_server.matches());
        assert_eq!(matches, Some(vec![]));

        let stopped = manager.shutdown_mock_server_by_port(server_port);
        assert!(stopped);

        // The tokio runtime is now out of tasks
        drop(manager);

        let ten_millis = time::Duration::from_millis(200);
        thread::sleep(ten_millis);

        // Server should be down
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_err());
    }
}
<|endoftext|>


<commit_before>use {Action, InputTranslator, InputRebind, MouseTranslationData, to_act_bt_hashmap};
use input::Button;
use window::Size;
use std::convert::Into;
use std::default::Default;

/// Convenience object for constructing an InputMap.
pub struct RebindBuilder<A: Action> {
    input_remappings: Vec<(Button, A)>,
    mouse_data: MouseTranslationData
}

impl<A: Action> RebindBuilder<A> {
    /// Creates a new `RebindBuilder` with the specified viewport size.
    pub fn new<S: Into<Size> + Sized>(size: S) -> Self {
        RebindBuilder {
            input_remappings: vec![],
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Set whether the x scroll is inverted on the builder.
    pub fn x_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_scroll_inverted = invert;
        self
    }

    /// Returns true if the x scroll is inverted on the builder.
    pub fn get_x_scroll_inverted(&self) -> bool {
        self.mouse_data.x_axis_scroll_inverted
    }

    /// Set whether the y scroll is inverted on the builder.
    pub fn y_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_scroll_inverted = invert;
        self
    }

    /// Returns true if the y scroll is inverted on the builder.
    pub fn get_y_scroll_inverted(&self) -> bool {
        self.mouse_data.y_axis_scroll_inverted
    }

    /// Set whether the x axis motion is inverted on the builder.
    pub fn x_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_motion_inverted = invert;
        self
    }

    /// Returns true if the x axis motion is inverted on the builder.
    pub fn get_x_motion_inverted(&self) -> bool {
        self.mouse_data.x_axis_motion_inverted
    }

    /// Set whether the y axis motion is inverted on the builder.
    pub fn y_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_motion_inverted = invert;
        self
    }

    /// Returns true if the y axis motion is inverted on the builder.
    pub fn get_y_motion_inverted(&self) -> bool {
        self.mouse_data.y_axis_motion_inverted
    }

    /// Set the mouse sensitivity.
    pub fn mouse_sensitivity(mut self, sensitivity: f64) -> Self {
        self.mouse_data.sensitivity = sensitivity;
        self
    }

    /// Returns the mouse sensitivity.
    pub fn get_mouse_sensitivity(&self) -> f64 {
        self.mouse_data.sensitivity
    }

    /// Sets the viewport size used for mouse position calculations.
    pub fn viewport_size(mut self, size: Size) -> Self {
        self.mouse_data.viewport_size = size;
        self
    }

    /// Returns the currently set viewport size.
    pub fn get_viewport_size(&self) -> Size {
        self.mouse_data.viewport_size
    }

    /// Add an association between the Button and Action.
    pub fn with_action_mapping(mut self, button: Button, action: A) -> Self {
        self.input_remappings.push((button, action));
        self
    }

    /// Creates an `InputTranslator` from this builder object.
    pub fn build_translator(self) -> InputTranslator<A> { self.into() }

    /// Creates an `InputRebind` from this builder object.
    pub fn build_rebind(self) -> InputRebind<A> { self.into() }
}

/// Creates a new `RebindBuilder`. The viewport size is set to (800, 600).
impl<A: Action> Default for RebindBuilder<A> {
    fn default() -> Self {
        Self::new((800, 600))
    }
}

impl<A: Action> Into<InputTranslator<A>> for RebindBuilder<A> {
    fn into(self) -> InputTranslator<A> {
        let mut input_map = InputTranslator::new(self.mouse_data.viewport_size);

        input_map.mouse_translator.data = self.mouse_data;
        input_map.keymap = self.input_remappings.iter().cloned().collect();

        input_map
    }
}

impl<A: Action> Into<InputRebind<A>> for RebindBuilder<A> {
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_data.viewport_size);

        input_rebind.mouse_data = self.mouse_data;
        input_rebind.keymap = to_act_bt_hashmap(self.input_remappings.iter().cloned());

        input_rebind
    }
}<commit_msg>Rename some variables for clarity<commit_after>use {Action, InputTranslator, InputRebind, MouseTranslationData, to_act_bt_hashmap};
use input::Button;
use window::Size;
use std::convert::Into;
use std::default::Default;

/// Convenience object for constructing an InputMap.
pub struct RebindBuilder<A: Action> {
    input_remappings: Vec<(Button, A)>,
    mouse_data: MouseTranslationData
}

impl<A: Action> RebindBuilder<A> {
    /// Creates a new `RebindBuilder` with the specified viewport size.
    pub fn new<S: Into<Size> + Sized>(size: S) -> Self {
        RebindBuilder {
            input_remappings: vec![],
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Set whether the x scroll is inverted on the builder.
    pub fn x_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_scroll_inverted = invert;
        self
    }

    /// Returns true if the x scroll is inverted on the builder.
    pub fn get_x_scroll_inverted(&self) -> bool {
        self.mouse_data.x_axis_scroll_inverted
    }

    /// Set whether the y scroll is inverted on the builder.
    pub fn y_scroll_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_scroll_inverted = invert;
        self
    }

    /// Returns true if the y scroll is inverted on the builder.
    pub fn get_y_scroll_inverted(&self) -> bool {
        self.mouse_data.y_axis_scroll_inverted
    }

    /// Set whether the x axis motion is inverted on the builder.
    pub fn x_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.x_axis_motion_inverted = invert;
        self
    }

    /// Returns true if the x axis motion is inverted on the builder.
    pub fn get_x_motion_inverted(&self) -> bool {
        self.mouse_data.x_axis_motion_inverted
    }

    /// Set whether the y axis motion is inverted on the builder.
    pub fn y_motion_inverted(mut self, invert: bool) -> Self {
        self.mouse_data.y_axis_motion_inverted = invert;
        self
    }

    /// Returns true if the y axis motion is inverted on the builder.
    pub fn get_y_motion_inverted(&self) -> bool {
        self.mouse_data.y_axis_motion_inverted
    }

    /// Set the mouse sensitivity.
    pub fn mouse_sensitivity(mut self, sensitivity: f64) -> Self {
        self.mouse_data.sensitivity = sensitivity;
        self
    }

    /// Returns the mouse sensitivity.
    pub fn get_mouse_sensitivity(&self) -> f64 {
        self.mouse_data.sensitivity
    }

    /// Sets the viewport size used for mouse position calculations.
    pub fn viewport_size(mut self, size: Size) -> Self {
        self.mouse_data.viewport_size = size;
        self
    }

    /// Returns the currently set viewport size.
    pub fn get_viewport_size(&self) -> Size {
        self.mouse_data.viewport_size
    }

    /// Add an association between the Button and Action.
    pub fn with_action_mapping(mut self, button: Button, action: A) -> Self {
        self.input_remappings.push((button, action));
        self
    }

    /// Creates an `InputTranslator` from this builder object.
    pub fn build_translator(self) -> InputTranslator<A> { self.into() }

    /// Creates an `InputRebind` from this builder object.
    pub fn build_rebind(self) -> InputRebind<A> { self.into() }
}

/// Creates a new `RebindBuilder`. The viewport size is set to (800, 600).
impl<A: Action> Default for RebindBuilder<A> {
    fn default() -> Self {
        Self::new((800, 600))
    }
}

impl<A: Action> Into<InputTranslator<A>> for RebindBuilder<A> {
    fn into(self) -> InputTranslator<A> {
        let mut translator = InputTranslator::new(self.mouse_data.viewport_size);

        translator.mouse_translator.data = self.mouse_data;
        translator.keymap = self.input_remappings.iter().cloned().collect();

        translator
    }
}

impl<A: Action> Into<InputRebind<A>> for RebindBuilder<A> {
    fn into(self) -> InputRebind<A> {
        let mut rebind = InputRebind::new(self.mouse_data.viewport_size);

        rebind.mouse_data = self.mouse_data;
        rebind.keymap = to_act_bt_hashmap(self.input_remappings.iter().cloned());

        rebind
    }
}<|endoftext|>


<commit_before>#![crate_name = "cat"]
#![allow(unstable)]

#![feature(box_syntax, unsafe_destructor)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

pub fn uumain(args: Vec<String>) -> isize {
    let program = args[0].as_slice();
    let opts = [
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank",
                         "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting",
                         "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to \
                             standard output.", &opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberingMode::NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberingMode::NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberingMode::NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(&["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(&["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(&["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);

    0
}

#[derive(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: usize = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        let mut in_buf  = [0; 1024 * 31];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = &in_buf[..n];
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf[pos..].iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(&in_buf[pos..pos + p]).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(&in_buf[pos..]).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: usize = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        // Flush all 1024 iterations.
        let mut flush_counter = range(0us, 1024);

        let mut in_buf  = [0; 1024 * 32];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf[..n].iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0us, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 ... 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 ... 31 => writer.write(&['^' as u8, byte + 64]),
                        127      => writer.write(&['^' as u8, byte - 64]),
                        _        => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0; 1024 * 64];

    for path in files.iter() {
        let (mut reader, _) = match open(path.as_slice()) {
            Some(x) => x,
            None => continue,
        };

        loop {
            match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(&in_buf[..n]).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberingMode::NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: usize,
    threshold: usize,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(&self.buf[..self.pos]);
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(&self.buf[..self.pos]).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    panic!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = &mut self.buf[self.pos..];
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<commit_msg>Cleanup cat: open files in for loop header.<commit_after>#![crate_name = "cat"]
#![allow(unstable)]

#![feature(box_syntax, unsafe_destructor)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

pub fn uumain(args: Vec<String>) -> isize {
    let program = args[0].as_slice();
    let opts = [
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank",
                         "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting",
                         "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to \
                             standard output.", &opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberingMode::NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberingMode::NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberingMode::NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(&["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(&["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(&["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);

    0
}

#[derive(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[])) {

        let mut in_buf  = [0; 1024 * 31];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = &in_buf[..n];
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf[pos..].iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(&in_buf[pos..pos + p]).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(&in_buf[pos..]).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: usize = 1;

    for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[])) {

        // Flush all 1024 iterations.
        let mut flush_counter = range(0us, 1024);

        let mut in_buf  = [0; 1024 * 32];
        let mut out_buf = [0; 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf[..n].iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0us, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberingMode::NumberAll {
                            (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberingMode::NumberNone {
                    (write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 ... 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 ... 31 => writer.write(&['^' as u8, byte + 64]),
                        127      => writer.write(&['^' as u8, byte - 64]),
                        _        => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0; 1024 * 64];

    for (mut reader, _) in files.iter().filter_map(|p| open(&p[])) {
        loop {
            match reader.read(&mut in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(&in_buf[..n]).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberingMode::NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: usize,
    threshold: usize,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(&self.buf[..self.pos]);
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(&self.buf[..self.pos]).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    panic!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = &mut self.buf[self.pos..];
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let block_byte  = bytes[0] >> 4;
      let sample_byte = bytes[0] & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_assignment = match bytes[0] >> 4 {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0000          => 0,
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        0b1111 => 0,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0011 => 0,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        0b0111 => 0,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<commit_msg>Check validity of the several bits<commit_after>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let block_byte  = bytes[0] >> 4;
      let sample_byte = bytes[0] & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_byte       = bytes[0] >> 4
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = channel_byte < 0b1011 &&
                      (size_byte != 0b0011 && size_byte != 0b0111) &&
                      (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0000          => 0,
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        0b1111 => 0,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0011 => 0,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        0b0111 => 0,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

pub const UNSTABLE_CHANNEL: &'static str = "unstable";
pub const STABLE_CHANNEL: &'static str = "stable";

/// Default Depot Channel environment variable
pub const DEPOT_CHANNEL_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";
<commit_msg>Tag scheduler builds with dynamic channel<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// 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.

pub const UNSTABLE_CHANNEL: &'static str = "unstable";
pub const STABLE_CHANNEL: &'static str = "stable";

/// Default Depot Channel environment variable
pub const DEPOT_CHANNEL_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";

/// Helper function for Builder dynamic channels
pub fn bldr_channel_name(id: u64) -> String {
    format!("bldr-{}", id)
}
<|endoftext|>