<commit_before>use webcore::value::{Value, Reference};
use webcore::try_from::TryInto;
use webapi::cross_origin_setting::CrossOriginSetting;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node};
use webapi::element::{IElement, Element};
use webapi::html_element::{IHtmlElement, HtmlElement};

/// The HTML image element is used to manipulate the layout and presentation of
/// `<img>` elements.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement)
pub struct ImageElement( Reference );

impl IEventTarget for ImageElement {}
impl INode for ImageElement {}
impl IElement for ImageElement {}
impl IHtmlElement for ImageElement {}

reference_boilerplate! {
    ImageElement,
    instanceof HTMLImageElement
    convertible to EventTarget
    convertible to Node
    convertible to Element
    convertible to HtmlElement
}

impl ImageElement {
    /// Constructs a new ImageElement.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image)
    pub fn new() -> ImageElement {
        js! (
            return new Image();
        ).try_into().unwrap()
    }

    /// Constructs a new ImageElement with the given width and height.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image)
    pub fn with_size(width: u32, height: u32) -> ImageElement {
        js! (
            return new Image(@{width}, @{height});
        ).try_into().unwrap()
    }

    /// Returns the HTML `alt` attribute, representing the fallback context for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt)
    #[inline]
    pub fn alt( &self ) -> String {
        js! (
            return @{self}.alt;
        ).try_into().unwrap()
    }

    /// Sets the HTML `alt` attribute, representing the fallback context for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt)
    pub fn set_alt( &self, value: &str ) {
        js! { @(no_return)
            @{self}.alt = @{value};
        }
    }

    /// Returns true if the browser has finished fetching the image, whether
    /// successful or not. It also return true if the image has no src value.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete)
    pub fn complete( &self ) -> bool {
        js! (
            return @{self}.complete;
        ).try_into().unwrap()
    }

    /// Returns the Cross-Origin Resource Sharing (CORS) setting for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin)
    pub fn cross_origin( &self ) -> CrossOriginSetting {
        match js!(
            return @{self}.crossOrigin;
        ) {
            Value::Null => CrossOriginSetting::None,
            Value::String( ref s ) if *s == "anonymous" => CrossOriginSetting::Anonymous,
            Value::String( ref s ) if *s == "use-credentials" => CrossOriginSetting::UseCredentials,
            _ => unreachable!("Unexpected crossOrigin value")
        }
    }

    /// Sets the Cross-Origin Resource Sharing (CORS) setting for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin)
    pub fn set_cross_origin( &self, value: CrossOriginSetting ) {
        js! { @(no_return)
            @{self}.crossOrigin = @{
                match value {
                    CrossOriginSetting::None => None,
                    CrossOriginSetting::Anonymous => Some("anonymous"),
                    CrossOriginSetting::UseCredentials => Some("use-credentials")
                }
            }
        }
    }

    /// Returns the the rendered height of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/height)
    pub fn height( &self ) -> u32 {
        js! (
            return @{self}.height;
        ).try_into().unwrap()
    }

    /// Sets the the rendered height of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/height)
    pub fn set_height( &self, value: u32 ) {
        js! { @(no_return)
            @{self}.height = @{value};
        }
    }

    /// Indicates whether the image is part of a server-side image map.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap)
    pub fn is_map( &self ) -> bool {
        js!(
            return @{self}.isMap;
        ).try_into().unwrap()
    }

    /// Sets whether the image is part of a server-side image map.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap)
    pub fn set_is_map( &self, value: bool ) {
        js! { @(no_return)
            @{self}.isMap = @{value};
        }
    }

    /// Returns the intrinsic height of the image in CSS pixels, if it is available;
    /// else, it returns 0.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalHeight)
    pub fn natural_height( &self ) -> u32 {
        js!(
            return @{self}.naturalHeight;
        ).try_into().unwrap()
    }

    /// Returns the intrinsic width of the image in CSS pixels, if it is available;
    /// else, it returns 0.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth)
    pub fn natural_width( &self ) -> u32 {
        js!(
            return @{self}.naturalWidth;
        ).try_into().unwrap()
    }

    /// Returns the full URL of the image, including the base URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/src)
    pub fn src( &self ) -> String {
        js! (
            return @{self}.src;
        ).try_into().unwrap()
    }

    /// Sets the full URL of the image, including the base URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/src)
    pub fn set_src( &self, value: &str ) {
        js! { @(no_return)
            @{self}.src = @{value};
        }
    }

    /// Returns the `usemap` HTML attribute, containing a partial URL of a map element.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/useMap)
    pub fn use_map( &self ) -> String {
        js!(
            return @{self}.useMap;
        ).try_into().unwrap()
    }

    /// Sets the `usemap` HTML attribute, containing a partial URL of a map element.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/useMap)
    pub fn set_use_map( &self, value: &str ) {
        js! { @(no_return)
             @{self}.useMap = @{value};
        }
    }

    /// Returns the rendered width of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/width)
    pub fn width( &self ) -> u32 {
        js! (
            return @{self}.width;
        ).try_into().unwrap()
    }

    /// Sets the rendered width of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/width)
    pub fn set_width( &self, value: u32 ) {
        js! { @(no_return)
            @{self}.width = @{value};
        }
    }
}

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

    #[test]
    fn test_new() {
        let image = ImageElement::new();
        assert_eq!(image.alt(), "");
    }

    #[test]
    fn test_with_size() {
        let image = ImageElement::with_size(333, 444);
        assert_eq!(image.width(), 333);
        assert_eq!(image.height(), 444);
    }

    #[test]
    fn test_alt() {
        let image = ImageElement::new();
        assert_eq!(image.alt(), "");
        image.set_alt("test");
        assert_eq!(image.alt(), "test");
    }

    #[test]
    fn test_complete() {
        let image = ImageElement::new();
        assert_eq!(image.complete(), true);
    }

    #[test]
    fn test_width_height() {
        let image = ImageElement::new();
        assert_eq!(image.width(), 0);
        assert_eq!(image.height(), 0);
        image.set_width(4);
        image.set_height(5);
        assert_eq!(image.width(), 4);
        assert_eq!(image.height(), 5);
    }

    #[test]
    fn test_src() {
        let image = ImageElement::new();
        assert_eq!(image.src(), "");
        image.set_src("http://example.com/image.gif");
        assert_eq!(image.src(), "http://example.com/image.gif");
    }

    #[test]
    fn test_use_map() {
        let image = ImageElement::new();
        assert_eq!(image.use_map(), "");
        image.set_use_map("test");
        assert_eq!(image.use_map(), "test");
    }

    #[test]
    fn test_natural_width_height() {
        let image = ImageElement::new();
        assert_eq!(image.natural_width(), 0);
        assert_eq!(image.natural_height(), 0);
    }

    #[test]
    fn test_cross_origin() {
        let image = ImageElement::new();
        assert_eq!(image.cross_origin(), CrossOriginSetting::None);
        image.set_cross_origin(CrossOriginSetting::Anonymous);
        assert_eq!(image.cross_origin(), CrossOriginSetting::Anonymous);
        image.set_cross_origin(CrossOriginSetting::UseCredentials);
        assert_eq!(image.cross_origin(), CrossOriginSetting::UseCredentials);
        image.set_cross_origin(CrossOriginSetting::None);
        assert_eq!(image.cross_origin(), CrossOriginSetting::None);
    }
}
<commit_msg>Return an Option in `ImageElement::natural_{width, height}`<commit_after>use webcore::value::{Value, Reference};
use webcore::try_from::TryInto;
use webapi::cross_origin_setting::CrossOriginSetting;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::node::{INode, Node};
use webapi::element::{IElement, Element};
use webapi::html_element::{IHtmlElement, HtmlElement};

/// The HTML image element is used to manipulate the layout and presentation of
/// `<img>` elements.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement)
pub struct ImageElement( Reference );

impl IEventTarget for ImageElement {}
impl INode for ImageElement {}
impl IElement for ImageElement {}
impl IHtmlElement for ImageElement {}

reference_boilerplate! {
    ImageElement,
    instanceof HTMLImageElement
    convertible to EventTarget
    convertible to Node
    convertible to Element
    convertible to HtmlElement
}

impl ImageElement {
    /// Constructs a new ImageElement.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image)
    pub fn new() -> ImageElement {
        js! (
            return new Image();
        ).try_into().unwrap()
    }

    /// Constructs a new ImageElement with the given width and height.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image)
    pub fn with_size(width: u32, height: u32) -> ImageElement {
        js! (
            return new Image(@{width}, @{height});
        ).try_into().unwrap()
    }

    /// Returns the HTML `alt` attribute, representing the fallback context for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt)
    #[inline]
    pub fn alt( &self ) -> String {
        js! (
            return @{self}.alt;
        ).try_into().unwrap()
    }

    /// Sets the HTML `alt` attribute, representing the fallback context for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt)
    pub fn set_alt( &self, value: &str ) {
        js! { @(no_return)
            @{self}.alt = @{value};
        }
    }

    /// Returns true if the browser has finished fetching the image, whether
    /// successful or not. It also return true if the image has no src value.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete)
    pub fn complete( &self ) -> bool {
        js! (
            return @{self}.complete;
        ).try_into().unwrap()
    }

    /// Returns the Cross-Origin Resource Sharing (CORS) setting for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin)
    pub fn cross_origin( &self ) -> CrossOriginSetting {
        match js!(
            return @{self}.crossOrigin;
        ) {
            Value::Null => CrossOriginSetting::None,
            Value::String( ref s ) if *s == "anonymous" => CrossOriginSetting::Anonymous,
            Value::String( ref s ) if *s == "use-credentials" => CrossOriginSetting::UseCredentials,
            _ => unreachable!("Unexpected crossOrigin value")
        }
    }

    /// Sets the Cross-Origin Resource Sharing (CORS) setting for the image.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin)
    pub fn set_cross_origin( &self, value: CrossOriginSetting ) {
        js! { @(no_return)
            @{self}.crossOrigin = @{
                match value {
                    CrossOriginSetting::None => None,
                    CrossOriginSetting::Anonymous => Some("anonymous"),
                    CrossOriginSetting::UseCredentials => Some("use-credentials")
                }
            }
        }
    }

    /// Returns the the rendered height of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/height)
    pub fn height( &self ) -> u32 {
        js! (
            return @{self}.height;
        ).try_into().unwrap()
    }

    /// Sets the the rendered height of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/height)
    pub fn set_height( &self, value: u32 ) {
        js! { @(no_return)
            @{self}.height = @{value};
        }
    }

    /// Indicates whether the image is part of a server-side image map.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap)
    pub fn is_map( &self ) -> bool {
        js!(
            return @{self}.isMap;
        ).try_into().unwrap()
    }

    /// Sets whether the image is part of a server-side image map.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap)
    pub fn set_is_map( &self, value: bool ) {
        js! { @(no_return)
            @{self}.isMap = @{value};
        }
    }

    /// Returns the intrinsic height of the image in CSS pixels, if it is available.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalHeight)
    pub fn natural_height( &self ) -> Option< u32 > {
        match js!(
            return @{self}.naturalHeight;
        ).try_into().unwrap() {
            0 => None,
            value => Some( value )
        }
    }

    /// Returns the intrinsic width of the image in CSS pixels, if it is available.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth)
    pub fn natural_width( &self ) -> Option< u32 > {
        match js!(
            return @{self}.naturalWidth;
        ).try_into().unwrap() {
            0 => None,
            value => Some( value )
        }
    }

    /// Returns the full URL of the image, including the base URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/src)
    pub fn src( &self ) -> String {
        js! (
            return @{self}.src;
        ).try_into().unwrap()
    }

    /// Sets the full URL of the image, including the base URI.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/src)
    pub fn set_src( &self, value: &str ) {
        js! { @(no_return)
            @{self}.src = @{value};
        }
    }

    /// Returns the `usemap` HTML attribute, containing a partial URL of a map element.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/useMap)
    pub fn use_map( &self ) -> String {
        js!(
            return @{self}.useMap;
        ).try_into().unwrap()
    }

    /// Sets the `usemap` HTML attribute, containing a partial URL of a map element.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/useMap)
    pub fn set_use_map( &self, value: &str ) {
        js! { @(no_return)
             @{self}.useMap = @{value};
        }
    }

    /// Returns the rendered width of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/width)
    pub fn width( &self ) -> u32 {
        js! (
            return @{self}.width;
        ).try_into().unwrap()
    }

    /// Sets the rendered width of the image in CSS pixels.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/width)
    pub fn set_width( &self, value: u32 ) {
        js! { @(no_return)
            @{self}.width = @{value};
        }
    }
}

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

    #[test]
    fn test_new() {
        let image = ImageElement::new();
        assert_eq!(image.alt(), "");
    }

    #[test]
    fn test_with_size() {
        let image = ImageElement::with_size(333, 444);
        assert_eq!(image.width(), 333);
        assert_eq!(image.height(), 444);
    }

    #[test]
    fn test_alt() {
        let image = ImageElement::new();
        assert_eq!(image.alt(), "");
        image.set_alt("test");
        assert_eq!(image.alt(), "test");
    }

    #[test]
    fn test_complete() {
        let image = ImageElement::new();
        assert_eq!(image.complete(), true);
    }

    #[test]
    fn test_width_height() {
        let image = ImageElement::new();
        assert_eq!(image.width(), 0);
        assert_eq!(image.height(), 0);
        image.set_width(4);
        image.set_height(5);
        assert_eq!(image.width(), 4);
        assert_eq!(image.height(), 5);
    }

    #[test]
    fn test_src() {
        let image = ImageElement::new();
        assert_eq!(image.src(), "");
        image.set_src("http://example.com/image.gif");
        assert_eq!(image.src(), "http://example.com/image.gif");
    }

    #[test]
    fn test_use_map() {
        let image = ImageElement::new();
        assert_eq!(image.use_map(), "");
        image.set_use_map("test");
        assert_eq!(image.use_map(), "test");
    }

    #[test]
    fn test_natural_width_height() {
        let image = ImageElement::new();
        assert_eq!(image.natural_width(), None);
        assert_eq!(image.natural_height(), None);
    }

    #[test]
    fn test_cross_origin() {
        let image = ImageElement::new();
        assert_eq!(image.cross_origin(), CrossOriginSetting::None);
        image.set_cross_origin(CrossOriginSetting::Anonymous);
        assert_eq!(image.cross_origin(), CrossOriginSetting::Anonymous);
        image.set_cross_origin(CrossOriginSetting::UseCredentials);
        assert_eq!(image.cross_origin(), CrossOriginSetting::UseCredentials);
        image.set_cross_origin(CrossOriginSetting::None);
        assert_eq!(image.cross_origin(), CrossOriginSetting::None);
    }
}
<|endoftext|>


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

use std::cell::Cell;
use std::ptr;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use libc::c_uint;
use ffi;
use glib::translate::*;
use gdk;

thread_local! {
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;

/// Asserts that this is the main thread and `gtk::init` has been called.
macro_rules! assert_initialized_main_thread {
    () => (
        if !::rt::is_initialized_main_thread() {
            if ::rt::is_initialized() {
                panic!("GTK may only be used from the main thread.");
            }
            else {
                panic!("GTK has not been initialized. Call `gtk::init` first.");
            }
        }
    )
}

/// No-op.
macro_rules! skip_assert_initialized {
    () => ()
}

/// Asserts that `gtk::init` has not been called.
macro_rules! assert_not_initialized {
    () => (
        if ::rt::is_initialized() {
            panic!("This function has to be called before `gtk::init`.");
        }
    )
}

macro_rules! callback_guard {
    () => (
        let _guard = ::glib::CallbackGuard::new();
        if cfg!(debug_assertions) {
            assert_initialized_main_thread!();
        }
    )
}

/// Returns `true` if GTK has been initialized.
#[inline]
pub fn is_initialized() -> bool {
    skip_assert_initialized!();
    INITIALIZED.load(Ordering::Acquire)
}

/// Returns `true` if GTK has been initialized and this is the main thread.
#[inline]
pub fn is_initialized_main_thread() -> bool {
    skip_assert_initialized!();
    IS_MAIN_THREAD.with(|c| c.get())
}

/// Informs this crate that GTK has been initialized and the current thread is the main one.
pub unsafe fn set_initialized() {
    skip_assert_initialized!();
    if is_initialized_main_thread() {
        return;
    }
    else if is_initialized() {
        panic!("Attempted to initialize GTK from two different threads.");
    }
    INITIALIZED.store(true, Ordering::Release);
    IS_MAIN_THREAD.with(|c| c.set(true));
}

/// Tries to initialize GTK+.
///
/// Call either this function or [`Application::new`][new] before using any
/// other GTK+ functions.
///
/// [new]: struct.Application.html#method.new
///
/// Note that this function calls `gtk_init_check()` rather than `gtk_init()`,
/// so will not cause the program to terminate if GTK could not be initialized.
/// Instead, an Ok is returned if the windowing system was successfully
/// initialized otherwise an Err is returned.
pub fn init() -> Result<(), ()> {
    skip_assert_initialized!();
    unsafe {
        let ok = from_glib(ffi::gtk_init_check(ptr::null_mut(), ptr::null_mut()));
        if ok {
            gdk::set_initialized();
            set_initialized();
            Ok(())
        }
        else {
            Err(())
        }
    }
}

pub fn main() {
    assert_initialized_main_thread!();
    unsafe {
        ffi::gtk_main();
    }
}

pub fn main_quit() {
    assert_initialized_main_thread!();
    unsafe {
        if ffi::gtk_main_level() > 0 {
            ffi::gtk_main_quit();
        }
        else if cfg!(debug_assertions) {
            panic!("Attempted to quit a GTK main loop when none is running.");
        }
    }
}

pub fn main_level() -> u32 {
    assert_initialized_main_thread!();
    unsafe {
        ffi::gtk_main_level() as u32
    }
}

pub fn main_iteration() -> bool {
    assert_initialized_main_thread!();
    unsafe { from_glib(ffi::gtk_main_iteration()) }
}

pub fn main_iteration_do(blocking: bool) -> bool {
    assert_initialized_main_thread!();
    unsafe { from_glib(ffi::gtk_main_iteration_do(blocking.to_glib())) }
}

pub fn events_pending() -> bool {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(ffi::gtk_events_pending())
    }
}

pub fn get_major_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_major_version() as u32
    }
}

pub fn get_minor_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_minor_version() as u32
    }
}

pub fn get_micro_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_micro_version() as u32
    }
}

pub fn get_binary_age() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_binary_age() as u32
    }
}

pub fn get_interface_age() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_interface_age() as u32
    }
}

pub fn check_version(required_major: u32, required_minor: u32, required_micro: u32) -> Option<String> {
    skip_assert_initialized!();
    unsafe {
        from_glib_none(
            ffi::gtk_check_version(required_major as c_uint, required_minor as c_uint, required_micro as c_uint))
    }
 }
<commit_msg>Add the "different threads" check to `init`<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::Cell;
use std::ptr;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use libc::c_uint;
use ffi;
use glib::translate::*;
use gdk;

thread_local! {
    static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;

/// Asserts that this is the main thread and `gtk::init` has been called.
macro_rules! assert_initialized_main_thread {
    () => (
        if !::rt::is_initialized_main_thread() {
            if ::rt::is_initialized() {
                panic!("GTK may only be used from the main thread.");
            }
            else {
                panic!("GTK has not been initialized. Call `gtk::init` first.");
            }
        }
    )
}

/// No-op.
macro_rules! skip_assert_initialized {
    () => ()
}

/// Asserts that `gtk::init` has not been called.
macro_rules! assert_not_initialized {
    () => (
        if ::rt::is_initialized() {
            panic!("This function has to be called before `gtk::init`.");
        }
    )
}

macro_rules! callback_guard {
    () => (
        let _guard = ::glib::CallbackGuard::new();
        if cfg!(debug_assertions) {
            assert_initialized_main_thread!();
        }
    )
}

/// Returns `true` if GTK has been initialized.
#[inline]
pub fn is_initialized() -> bool {
    skip_assert_initialized!();
    INITIALIZED.load(Ordering::Acquire)
}

/// Returns `true` if GTK has been initialized and this is the main thread.
#[inline]
pub fn is_initialized_main_thread() -> bool {
    skip_assert_initialized!();
    IS_MAIN_THREAD.with(|c| c.get())
}

/// Informs this crate that GTK has been initialized and the current thread is the main one.
pub unsafe fn set_initialized() {
    skip_assert_initialized!();
    if is_initialized_main_thread() {
        return;
    }
    else if is_initialized() {
        panic!("Attempted to initialize GTK from two different threads.");
    }
    gdk::set_initialized();
    INITIALIZED.store(true, Ordering::Release);
    IS_MAIN_THREAD.with(|c| c.set(true));
}

/// Tries to initialize GTK+.
///
/// Call either this function or [`Application::new`][new] before using any
/// other GTK+ functions.
///
/// [new]: struct.Application.html#method.new
///
/// Note that this function calls `gtk_init_check()` rather than `gtk_init()`,
/// so will not cause the program to terminate if GTK could not be initialized.
/// Instead, an Ok is returned if the windowing system was successfully
/// initialized otherwise an Err is returned.
pub fn init() -> Result<(), ()> {
    skip_assert_initialized!();
    if is_initialized_main_thread() {
        return Ok(());
    }
    else if is_initialized() {
        panic!("Attempted to initialize GTK from two different threads.");
    }
    unsafe {
        if from_glib(ffi::gtk_init_check(ptr::null_mut(), ptr::null_mut())) {
            set_initialized();
            Ok(())
        }
        else {
            Err(())
        }
    }
}

pub fn main() {
    assert_initialized_main_thread!();
    unsafe {
        ffi::gtk_main();
    }
}

pub fn main_quit() {
    assert_initialized_main_thread!();
    unsafe {
        if ffi::gtk_main_level() > 0 {
            ffi::gtk_main_quit();
        }
        else if cfg!(debug_assertions) {
            panic!("Attempted to quit a GTK main loop when none is running.");
        }
    }
}

pub fn main_level() -> u32 {
    assert_initialized_main_thread!();
    unsafe {
        ffi::gtk_main_level() as u32
    }
}

pub fn main_iteration() -> bool {
    assert_initialized_main_thread!();
    unsafe { from_glib(ffi::gtk_main_iteration()) }
}

pub fn main_iteration_do(blocking: bool) -> bool {
    assert_initialized_main_thread!();
    unsafe { from_glib(ffi::gtk_main_iteration_do(blocking.to_glib())) }
}

pub fn events_pending() -> bool {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(ffi::gtk_events_pending())
    }
}

pub fn get_major_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_major_version() as u32
    }
}

pub fn get_minor_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_minor_version() as u32
    }
}

pub fn get_micro_version() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_micro_version() as u32
    }
}

pub fn get_binary_age() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_binary_age() as u32
    }
}

pub fn get_interface_age() -> u32 {
    skip_assert_initialized!();
    unsafe {
        ffi::gtk_get_interface_age() as u32
    }
}

pub fn check_version(required_major: u32, required_minor: u32, required_micro: u32) -> Option<String> {
    skip_assert_initialized!();
    unsafe {
        from_glib_none(
            ffi::gtk_check_version(required_major as c_uint, required_minor as c_uint, required_micro as c_uint))
    }
 }
<|endoftext|>


<commit_before>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use super::Ixs;

// [a:b:s] syntax for example [:3], [::-1]
// [0,:] -- first row of matrix
// [:,0] -- first column of matrix

#[derive(Copy, PartialEq, Eq, Hash, Debug)]
/// A slice, a description of a range of an array axis.
///
/// Fields are `begin`, `end` and `stride`, where
/// negative `begin` or `end` indexes are counted from the back
/// of the axis.
///
/// If `end` is `None`, the slice extends to the end of the axis.
///
/// See also the [`s![] macro`](macro.s!.html), a convenient way to specify
/// an array of `Si`.
///
/// ## Examples
///
/// `Si(0, None, 1)` is the full range of an axis.
/// Python equivalent is `[:]`. Macro equivalent is `s![..]`.
///
/// `Si(a, Some(b), 2)` is every second element from `a` until `b`.
/// Python equivalent is `[a:b:2]`. Macro equivalent is `s![a..b;2]`.
///
/// `Si(a, None, -1)` is every element, from `a`
/// until the end, in reverse order. Python equivalent is `[a::-1]`.
/// Macro equivalent is `s![a..;-1]`.
///
/// The constant [`S`] is a shorthand for the full range of an axis.
/// [`S`]: constant.S.html
pub struct Si(pub Ixs, pub Option<Ixs>, pub Ixs);

impl From<Range<Ixs>> for Si {
    #[inline]
    fn from(r: Range<Ixs>) -> Si {
        Si(r.start, Some(r.end), 1)
    }
}

impl From<RangeFrom<Ixs>> for Si {
    #[inline]
    fn from(r: RangeFrom<Ixs>) -> Si {
        Si(r.start, None, 1)
    }
}

impl From<RangeTo<Ixs>> for Si {
    #[inline]
    fn from(r: RangeTo<Ixs>) -> Si {
        Si(0, Some(r.end), 1)
    }
}

impl From<RangeFull> for Si {
    #[inline]
    fn from(_: RangeFull) -> Si {
        S
    }
}

impl Si {
    #[inline]
    pub fn step(self, step: Ixs) -> Self {
        Si(self.0, self.1, self.2 * step)
    }
}

impl Clone for Si {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

/// Slice value for the full range of an axis.
pub const S: Si = Si(0, None, 1);

/// Slice argument constructor.
///
/// `s![]` takes a list of ranges, separated by comma, with optional strides
/// that are separated from the range by a semicolon.
/// It is converted into a slice argument with type `&[Si; N]`.
///
/// Each range uses signed indices, where a negative value is counted from
/// the end of the axis. Strides are also signed and may be negative, but
/// must not be zero.
///
/// For example `s![0..4;2, 1..5]` is a slice of rows 0..4 with step size 2,
/// and columns 1..5 with default step size 1. The slice would have
/// shape `[2, 4]`.
///
/// If an array has two axes, the slice argument is passed as
/// type `&[Si; 2]`.  The macro expansion of `s![a..b;c, d..e]`
/// is equivalent to `&[Si(a, Some(b), c), Si(d, Some(e), 1)]`.
///
/// ```
/// #[macro_use]
/// extern crate ndarray;
///
/// use ndarray::{
///     ArrayView,
///     Ix,
///     Array,
/// };
///
/// fn laplacian(v: &ArrayView<f32, (Ix, Ix)>) -> Array<f32, (Ix, Ix)> {
///     -4. * &v.slice(s![1..-1, 1..-1])
///     + v.slice(s![ ..-2, 1..-1])
///     + v.slice(s![1..-1,  ..-2])
///     + v.slice(s![1..-1, 2..  ])
///     + v.slice(s![2..  , 1..-1])
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! s(
    (@as_expr $e:expr) => ($e);
    // convert a..b;c into @step(a..b, c), final item
    (@parse [$($stack:tt)*] $r:expr;$s:expr) => {
        s![@as_expr &[$($stack)* s!(@step $r, $s)]]
    };
    // convert a..b into @step(a..b, 1), final item
    (@parse [$($stack:tt)*] $r:expr) => {
        s![@as_expr &[$($stack)* s!(@step $r, 1)]]
    };
    // convert a..b;c into @step(a..b, c)
    (@parse [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
        s![@parse [$($stack)* s!(@step $r, $s),] $($t)*]
    };
    // convert a..b into @step(a..b, 1)
    (@parse [$($stack:tt)*] $r:expr, $($t:tt)*) => {
        s![@parse [$($stack)* s!(@step $r, 1),] $($t)*]
    };
    // convert range, step into Si
    (@step $r:expr, $s:expr) => {
        <$crate::Si as ::std::convert::From<_>>::from($r).step($s)
    };
    ($($t:tt)*) => {
        s![@parse [] $($t)*]
    };
);
<commit_msg>Fix doctest for s![]<commit_after>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::{Range, RangeFrom, RangeTo, RangeFull};
use super::Ixs;

// [a:b:s] syntax for example [:3], [::-1]
// [0,:] -- first row of matrix
// [:,0] -- first column of matrix

#[derive(Copy, PartialEq, Eq, Hash, Debug)]
/// A slice, a description of a range of an array axis.
///
/// Fields are `begin`, `end` and `stride`, where
/// negative `begin` or `end` indexes are counted from the back
/// of the axis.
///
/// If `end` is `None`, the slice extends to the end of the axis.
///
/// See also the [`s![] macro`](macro.s!.html), a convenient way to specify
/// an array of `Si`.
///
/// ## Examples
///
/// `Si(0, None, 1)` is the full range of an axis.
/// Python equivalent is `[:]`. Macro equivalent is `s![..]`.
///
/// `Si(a, Some(b), 2)` is every second element from `a` until `b`.
/// Python equivalent is `[a:b:2]`. Macro equivalent is `s![a..b;2]`.
///
/// `Si(a, None, -1)` is every element, from `a`
/// until the end, in reverse order. Python equivalent is `[a::-1]`.
/// Macro equivalent is `s![a..;-1]`.
///
/// The constant [`S`] is a shorthand for the full range of an axis.
/// [`S`]: constant.S.html
pub struct Si(pub Ixs, pub Option<Ixs>, pub Ixs);

impl From<Range<Ixs>> for Si {
    #[inline]
    fn from(r: Range<Ixs>) -> Si {
        Si(r.start, Some(r.end), 1)
    }
}

impl From<RangeFrom<Ixs>> for Si {
    #[inline]
    fn from(r: RangeFrom<Ixs>) -> Si {
        Si(r.start, None, 1)
    }
}

impl From<RangeTo<Ixs>> for Si {
    #[inline]
    fn from(r: RangeTo<Ixs>) -> Si {
        Si(0, Some(r.end), 1)
    }
}

impl From<RangeFull> for Si {
    #[inline]
    fn from(_: RangeFull) -> Si {
        S
    }
}

impl Si {
    #[inline]
    pub fn step(self, step: Ixs) -> Self {
        Si(self.0, self.1, self.2 * step)
    }
}

impl Clone for Si {
    #[inline]
    fn clone(&self) -> Self {
        *self
    }
}

/// Slice value for the full range of an axis.
pub const S: Si = Si(0, None, 1);

/// Slice argument constructor.
///
/// `s![]` takes a list of ranges, separated by comma, with optional strides
/// that are separated from the range by a semicolon.
/// It is converted into a slice argument with type `&[Si; N]`.
///
/// Each range uses signed indices, where a negative value is counted from
/// the end of the axis. Strides are also signed and may be negative, but
/// must not be zero.
///
/// For example `s![0..4;2, 1..5]` is a slice of rows 0..4 with step size 2,
/// and columns 1..5 with default step size 1. The slice would have
/// shape `[2, 4]`.
///
/// If an array has two axes, the slice argument is passed as
/// type `&[Si; 2]`.  The macro expansion of `s![a..b;c, d..e]`
/// is equivalent to `&[Si(a, Some(b), c), Si(d, Some(e), 1)]`.
///
/// ```
/// #[macro_use]
/// extern crate ndarray;
///
/// use ndarray::{Array2, ArrayView2};
///
/// fn laplacian(v: &ArrayView2<f32>) -> Array2<f32> {
///     -4. * &v.slice(s![1..-1, 1..-1])
///     + v.slice(s![ ..-2, 1..-1])
///     + v.slice(s![1..-1,  ..-2])
///     + v.slice(s![1..-1, 2..  ])
///     + v.slice(s![2..  , 1..-1])
/// }
/// # fn main() { }
/// ```
#[macro_export]
macro_rules! s(
    (@as_expr $e:expr) => ($e);
    // convert a..b;c into @step(a..b, c), final item
    (@parse [$($stack:tt)*] $r:expr;$s:expr) => {
        s![@as_expr &[$($stack)* s!(@step $r, $s)]]
    };
    // convert a..b into @step(a..b, 1), final item
    (@parse [$($stack:tt)*] $r:expr) => {
        s![@as_expr &[$($stack)* s!(@step $r, 1)]]
    };
    // convert a..b;c into @step(a..b, c)
    (@parse [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
        s![@parse [$($stack)* s!(@step $r, $s),] $($t)*]
    };
    // convert a..b into @step(a..b, 1)
    (@parse [$($stack:tt)*] $r:expr, $($t:tt)*) => {
        s![@parse [$($stack)* s!(@step $r, 1),] $($t)*]
    };
    // convert range, step into Si
    (@step $r:expr, $s:expr) => {
        <$crate::Si as ::std::convert::From<_>>::from($r).step($s)
    };
    ($($t:tt)*) => {
        s![@parse [] $($t)*]
    };
);
<|endoftext|>


<commit_before>use std::char;
use std::num::Zero;
use std::os;

use ncurses::*;

use data;
use exec;

struct State {
    hosts: data::Hosts,
    selected: uint
}

impl State {
    #[inline]
    fn new(hosts: data::Hosts) -> State {
        State {
            hosts: hosts,
            selected: 0
        }
    }

    fn move_up(&mut self) {
        if self.selected > 0 {
            self.selected -= 1;
        }
    }

    fn move_down(&mut self) {
        if self.selected < self.hosts.hosts.len()-1 {
            self.selected += 1;
        }
    }

    fn find_selected(&self) -> &String {
        for (n, k) in self.hosts.hosts.keys().enumerate() {
            if n == self.selected { return k; }
        }
        unreachable!()
    }
}

fn num_len<N: Div<N, N>+Zero+PartialEq+FromPrimitive>(mut n: N) -> uint {
    let mut r = 0;
    while { n = n / FromPrimitive::from_u8(10).unwrap(); r += 1; n != Zero::zero() } {}
    r
}

fn compute_widths(hosts: &data::Hosts) -> (uint, uint, uint, uint) {
    if hosts.hosts.is_empty() { return (0, 0, 0, 0) }

    let number_width = num_len(hosts.hosts.len());
    let name_width = hosts.hosts.keys().map(|k| k.len()).max().unwrap();
    let addr_width = hosts.hosts.values()
        .map(|v| v.user.len() + v.host.len() + num_len(v.port) as uint + 2)
        .max().unwrap();
    let key_width = hosts.hosts.values()
        .flat_map(|v| v.key.as_ref().map(|k| k[]).into_iter())
        .map(|s| s.len())
        .max().unwrap();
    let max_width = number_width + 2 + name_width + 3 + addr_width + 3 + key_width;
    (number_width, name_width, addr_width, max_width)
}

fn render(state: &mut State) {
    let (number_width, name_width, addr_width, max_width) = compute_widths(&state.hosts);

    for (n, (name, h)) in state.hosts.hosts.iter().enumerate() {
        let (c_x, c_y) = (5, 3+n as i32);

        let addr = format!("{}@{}:{}", h.user, h.host, h.port);
        let mut s = format!("{0:1$u}. {2:3$s} - {4:5$s}",
                            n+1, number_width, name[], name_width, addr, addr_width);
        if let Some(ref key) = h.key {
            s.push_str(" - ");
            s.push_str(key[]);
        }

        mvprintw(c_y, c_x, s[]);

        mv(c_y, c_x);
        if n == state.selected {
            chgat(max_width as i32, A_REVERSE(), 0);
        } else {
            chgat(max_width as i32, A_NORMAL(), 0);
        }
    }

    mvprintw(3 + state.hosts.hosts.len() as i32 + 3, 5,
             "q to exit, up/down/k/j to move selection, enter to confirm");
}

fn execute(state: &mut State) -> ! {
    endwin();

    let args = state.hosts.hosts[*state.find_selected()].to_cmd_line();
    fn wrap_quotes_if_needed(s: &String) -> String {
        if s[].find(char::is_whitespace).is_some() {
            format!("'{}'", s)
        } else {
            s.clone()
        }
    }
    println!("Executing ssh {}...",
             args.iter().map(wrap_quotes_if_needed).collect::<Vec<String>>().connect(" "));

    exec::exec("ssh", args);
    fail!("Cannot execute ssh: {}", os::last_os_error());
}

fn react(state: &mut State) -> bool {
    macro_rules! one_of(
        ($e:expr ~ $($p:expr),+) => (
            $($e == $p as i32 ||)+ false
        )
    )
    let ch = getch();
    match ch {
        c if one_of!(c ~ KEY_UP,   b'k') => state.move_up(),
        c if one_of!(c ~ KEY_DOWN, b'j') => state.move_down(),
        c if c == b'\n' as i32 => execute(state),
        c if c == b'q' as i32 => return false,
        _ => {}
    }
    true
}

fn init_ui() {
    initscr();
    cbreak();
    keypad(stdscr, true);
    noecho();
}

pub fn start(hosts: data::Hosts) {
    init_ui();

    let mut state = State::new(hosts);
    loop {
        render(&mut state);
        if !react(&mut state) {
            break;
        }
    }

    endwin();
}

#[cfg(test)]
mod tests {
    use super::{num_len, compute_widths};

    use data;

    macro_rules! smap(
        ($($k:expr -> $v:expr),*) => ({
            let mut hm = ::std::collections::HashMap::new();
            $(hm.insert($k.to_string(), $v);)*
            hm
        })
    )

    #[test]
    fn test_num_len() {
        assert_eq!(1, num_len(0u));
        assert_eq!(1, num_len(1i));
        assert_eq!(1, num_len(7u16));
        assert_eq!(2, num_len(82i32));
        assert_eq!(16, num_len(1234567812345678u64));
    }

    #[test]
    fn test_compute_widths() {
        let h = data::Hosts {
            hosts: smap![
                "first-name" -> data::Host::new("abcd", 22, "host-1", Some("key.pem")),
                "second-name" -> data::Host::new("de", 1234, "longer-host", None)
            ]
        };
        assert_eq!((1, 11, 19), compute_widths(&h));
    }
}
<commit_msg>Fixed an error when no single key is configured<commit_after>use std::char;
use std::num::Zero;
use std::os;

use ncurses::*;

use data;
use exec;

struct State {
    hosts: data::Hosts,
    selected: uint
}

impl State {
    #[inline]
    fn new(hosts: data::Hosts) -> State {
        State {
            hosts: hosts,
            selected: 0
        }
    }

    fn move_up(&mut self) {
        if self.selected > 0 {
            self.selected -= 1;
        }
    }

    fn move_down(&mut self) {
        if self.selected < self.hosts.hosts.len()-1 {
            self.selected += 1;
        }
    }

    fn find_selected(&self) -> &String {
        for (n, k) in self.hosts.hosts.keys().enumerate() {
            if n == self.selected { return k; }
        }
        unreachable!()
    }
}

fn num_len<N: Div<N, N>+Zero+PartialEq+FromPrimitive>(mut n: N) -> uint {
    let mut r = 0;
    while { n = n / FromPrimitive::from_u8(10).unwrap(); r += 1; n != Zero::zero() } {}
    r
}

fn compute_widths(hosts: &data::Hosts) -> (uint, uint, uint, uint) {
    if hosts.hosts.is_empty() { return (0, 0, 0, 0) }

    let number_width = num_len(hosts.hosts.len());
    let name_width = hosts.hosts.keys().map(|k| k.len()).max().unwrap();
    let addr_width = hosts.hosts.values()
        .map(|v| v.user.len() + v.host.len() + num_len(v.port) as uint + 2)
        .max().unwrap();
    let key_width = hosts.hosts.values()
        .flat_map(|v| v.key.as_ref().map(|k| k[]).into_iter())
        .map(|s| s.len())
        .max();
    let max_width = number_width + 2 + name_width + 3 + addr_width +
                    key_width.map(|w| 3 + w).unwrap_or(0);
    (number_width, name_width, addr_width, max_width)
}

fn render(state: &mut State) {
    let (number_width, name_width, addr_width, max_width) = compute_widths(&state.hosts);

    for (n, (name, h)) in state.hosts.hosts.iter().enumerate() {
        let (c_x, c_y) = (5, 3+n as i32);

        let addr = format!("{}@{}:{}", h.user, h.host, h.port);
        let mut s = format!("{0:1$u}. {2:3$s} - {4:5$s}",
                            n+1, number_width, name[], name_width, addr, addr_width);
        if let Some(ref key) = h.key {
            s.push_str(" - ");
            s.push_str(key[]);
        }

        mvprintw(c_y, c_x, s[]);

        mv(c_y, c_x);
        if n == state.selected {
            chgat(max_width as i32, A_REVERSE(), 0);
        } else {
            chgat(max_width as i32, A_NORMAL(), 0);
        }
    }

    mvprintw(3 + state.hosts.hosts.len() as i32 + 3, 5,
             "q to exit, up/down/k/j to move selection, enter to confirm");
}

fn execute(state: &mut State) -> ! {
    endwin();

    let args = state.hosts.hosts[*state.find_selected()].to_cmd_line();
    fn wrap_quotes_if_needed(s: &String) -> String {
        if s[].find(char::is_whitespace).is_some() {
            format!("'{}'", s)
        } else {
            s.clone()
        }
    }
    println!("Executing ssh {}...",
             args.iter().map(wrap_quotes_if_needed).collect::<Vec<String>>().connect(" "));

    exec::exec("ssh", args);
    fail!("Cannot execute ssh: {}", os::last_os_error());
}

fn react(state: &mut State) -> bool {
    macro_rules! one_of(
        ($e:expr ~ $($p:expr),+) => (
            $($e == $p as i32 ||)+ false
        )
    )
    let ch = getch();
    match ch {
        c if one_of!(c ~ KEY_UP,   b'k') => state.move_up(),
        c if one_of!(c ~ KEY_DOWN, b'j') => state.move_down(),
        c if c == b'\n' as i32 => execute(state),
        c if c == b'q' as i32 => return false,
        _ => {}
    }
    true
}

fn init_ui() {
    initscr();
    cbreak();
    keypad(stdscr, true);
    noecho();
}

pub fn start(hosts: data::Hosts) {
    init_ui();

    let mut state = State::new(hosts);
    loop {
        render(&mut state);
        if !react(&mut state) {
            break;
        }
    }

    endwin();
}

#[cfg(test)]
mod tests {
    use super::{num_len, compute_widths};

    use data;

    macro_rules! smap(
        ($($k:expr -> $v:expr),*) => ({
            let mut hm = ::std::collections::HashMap::new();
            $(hm.insert($k.to_string(), $v);)*
            hm
        })
    )

    #[test]
    fn test_num_len() {
        assert_eq!(1, num_len(0u));
        assert_eq!(1, num_len(1i));
        assert_eq!(1, num_len(7u16));
        assert_eq!(2, num_len(82i32));
        assert_eq!(16, num_len(1234567812345678u64));
    }

    #[test]
    fn test_compute_widths() {
        let h = data::Hosts {
            hosts: smap![
                "first-name" -> data::Host::new("abcd", 22, "host-1", Some("key.pem")),
                "second-name" -> data::Host::new("de", 1234, "longer-host", None)
            ]
        };
        assert_eq!((1, 11, 19), compute_widths(&h));
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Write,Read};
use command::Command;

type Cell = u8;

pub struct VM {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: Box<Write>
}

impl VM {
    pub fn new(out: Option<Box<Write>>) -> VM {
        let stdout = out.unwrap_or_else(|| Box::new(io::stdout()));
        VM { cells: [0; 30_000], data_pointer: 0, out: stdout }
    }

    pub fn output(&mut self) {
        self.out
            .write_fmt(format_args!("{}", self.cells[self.data_pointer] as char))
            .expect("Could not output current byte");
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new(None);
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new(None);
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new(None);
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut vm = VM::new(None);
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut vm = VM::new(None);
        vm.data_pointer  = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<commit_msg>Change VM.out from Box<Write> to &mut Write<commit_after>use std::io;
use std::io::{Write,Read};
use command::Command;

type Cell = u8;

pub struct VM <'a> {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: &'a mut Write
}

impl <'a> VM <'a> {
    pub fn new(out: &mut Write) -> VM {
        VM { cells: [0; 30_000], data_pointer: 0, out }
    }

    pub fn output(&mut self) {
        self.out
            .write_fmt(format_args!("{}", self.cells[self.data_pointer] as char))
            .expect("Could not output current byte");
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => match res {
                Ok(value) => self.cells[self.data_pointer] = value,
                Err(error) => panic!(error),
            },
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer]
            .checked_sub(1)
            .unwrap_or(Cell::max_value());
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {},
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let vm = VM::new(None);
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut vm = VM::new(None);
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut vm = VM::new(None);
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut vm = VM::new(None);
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut vm = VM::new(None);
        vm.data_pointer  = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<|endoftext|>


<commit_before>use autograd::{Function, FuncIntf, FuncDelegate, Variable, FIWrap};
use macros::*;
use tensor::TensorKindList;
use ::*;

impl_func!(LinearF);

impl FuncIntf for LinearF {
    fn forward(&mut self, mut input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
    fn backward(&mut self, mut input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
}
<commit_msg>add forward for linear<commit_after>use autograd::{Function, FuncIntf, FuncDelegate, FIWrap};
use tensor::*;

impl_func!(LinearF);

impl FuncIntf for LinearF {
    fn forward(&mut self, input_list: &mut TensorKindList) -> TensorKindList {
        self.save_for_backward(input_list);
        let (input, weight) = (input_list.remove(0), input_list.remove(0));
        let mut output = input.new_([input.size()[0], weight.size()[0]]);
        output = output.addmm_(&0.into(), &1.into(), &input, &weight.t());
        if input_list.len() != 0 {
            let bias = input_list.remove(0);
            output = output.clone().addt_(&1.into(), &bias.expand_as(&output));
        }

        vec![output]
    }
    fn backward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use codespan::{ByteIndex, FileId, Files, LineIndex, Location, Span};
use std::ffi::OsStr;
use std::io;
use termcolor::WriteColor;

use crate::diagnostic::Label;
use crate::term::Config;

use super::{Locus, NewLine};

mod border;
mod gutter;
mod note;
mod underline;

use self::border::{BorderLeft, BorderLeftBreak, BorderTop, BorderTopLeft};
use self::gutter::Gutter;
use self::note::Note;
use self::underline::{Underline, UnderlineBottom, UnderlineLeft, UnderlineTop, UnderlineTopLeft};

pub use self::underline::MarkStyle;

/// An underlined snippet of source code.
///
/// ```text
///   ┌── test:2:9 ───
///   │
/// 2 │ (+ test "")
///   │         ^^ expected `Int` but found `String`
///   │
///   = expected type `Int`
///        found type `String`
/// ```
pub struct SourceSnippet<'a, Source>
where
    Source: AsRef<str>,
{
    files: &'a Files<Source>,
    file_id: FileId,
    spans: Vec<(&'a Label, MarkStyle)>,
    notes: &'a [String],
}

impl<'a, Source> SourceSnippet<'a, Source>
where
    Source: AsRef<str>,
{
    pub fn new(
        files: &'a Files<Source>,
        file_id: FileId,
        spans: Vec<(&'a Label, MarkStyle)>,
        notes: &'a [String],
    ) -> Self {
        SourceSnippet {
            files,
            file_id,
            spans,
            notes,
        }
    }

    fn file_name(&self) -> &'a OsStr {
        self.files.name(self.file_id)
    }

    fn source_locus_spans(&self) -> (Span, Span) {
        fn merge(span0: Span, span1: Span) -> Span {
            let start = std::cmp::min(span0.start(), span1.start());
            let end = std::cmp::max(span0.end(), span1.end());
            Span::new(start, end)
        }

        let mut source_span = None;
        let mut locus_span = None;

        for (label, mark_style) in &self.spans {
            source_span = Some(source_span.map_or(label.span, |span| merge(span, label.span)));
            if let MarkStyle::Primary(_) = mark_style {
                locus_span = Some(locus_span.map_or(label.span, |span| merge(span, label.span)));
            }
        }

        let source_span = source_span.unwrap_or(Span::initial());
        let locus_span = locus_span.unwrap_or(source_span);

        (source_span, locus_span)
    }

    fn location(&self, byte_index: ByteIndex) -> Result<Location, impl std::error::Error> {
        self.files.location(self.file_id, byte_index)
    }

    fn source_slice(&self, span: Span, tab: &'a str) -> Result<String, impl std::error::Error> {
        // NOTE: Not sure if we can do this more efficiently? Perhaps a custom
        // writer might be better?
        self.files
            .source_slice(self.file_id, span)
            .map(|s| s.replace('\t', tab))
    }

    fn line_span(&self, line_index: LineIndex) -> Result<Span, impl std::error::Error> {
        self.files.line_span(self.file_id, line_index)
    }

    pub fn emit(&self, writer: &mut (impl WriteColor + ?Sized), config: &Config) -> io::Result<()> {
        let (source_span, locus_span) = self.source_locus_spans();
        let locus_start = self.location(locus_span.start()).expect("locus_span_start");
        let source_end = self.location(source_span.end()).expect("source_span_end");

        // Use the length of the last line number as the gutter padding
        let gutter_padding = format!("{}", source_end.line.number()).len();
        // Cache the tabs we'll be using to pad the source strings.
        let tab = config.tab_padding();

        // Top left border and locus.
        //
        // ```text
        // ┌── test:2:9 ───
        // ```

        Gutter::new(None, gutter_padding).emit(writer, config)?;
        BorderTopLeft::new().emit(writer, config)?;
        BorderTop::new(2).emit(writer, config)?;
        write!(writer, " ")?;

        Locus::new(self.file_name(), locus_start).emit(writer, config)?;

        write!(writer, " ")?;
        BorderTop::new(3).emit(writer, config)?;
        NewLine::new().emit(writer, config)?;

        // TODO: Better grouping
        for (i, (label, mark_style)) in self.spans.iter().enumerate() {
            let start = self.location(label.span.start()).expect("location_start");
            let end = self.location(label.span.end()).expect("location_end");
            let start_line_span = self.line_span(start.line).expect("start_line_span");
            let end_line_span = self.line_span(end.line).expect("end_line_span");

            let label_style = mark_style.label_style(config);

            // Code snippet
            //
            // ```text
            //   │
            // 2 │ (+ test "")
            //   │         ^^ expected `Int` but found `String`
            //   │
            // ```

            // Write initial border
            Gutter::new(None, gutter_padding).emit(writer, config)?;
            match i {
                0 => BorderLeft::new().emit(writer, config)?,
                _ => BorderLeftBreak::new().emit(writer, config)?,
            }
            NewLine::new().emit(writer, config)?;

            // Write underlined source section
            if start.line == end.line {
                // Single line
                //
                // ```text
                // 2 │ (+ test "")
                //   │         ^^ expected `Int` but found `String`
                // ```

                let prefix_source = {
                    let span = Span::new(start_line_span.start(), label.span.start());
                    self.source_slice(span, &tab).expect("prefix_source")
                };
                let highlighted_source = {
                    let span = label.span;
                    self.source_slice(span, &tab).expect("highlighted_source")
                };
                let suffix_source = {
                    let span = Span::new(label.span.end(), end_line_span.end());
                    self.source_slice(span, &tab).expect("suffix_source")
                };

                // Write line number and border
                Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;

                // Write line source
                write!(writer, " {}", prefix_source)?;
                writer.set_color(label_style)?;
                write!(writer, "{}", highlighted_source)?;
                writer.reset()?;
                write!(writer, "{}", suffix_source.trim_end())?;
                NewLine::new().emit(writer, config)?;

                // Write border, underline, and label
                Gutter::new(None, gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                Underline::new(
                    *mark_style,
                    &prefix_source,
                    &highlighted_source,
                    &label.message,
                )
                .emit(writer, config)?;
                NewLine::new().emit(writer, config)?;
            } else {
                // Multiple lines
                //
                // ```text
                // 4 │   fizz₁ num = case (mod num 5) (mod num 3) of
                //   │ ╭─────────────^
                // 5 │ │     0 0 => "FizzBuzz"
                // 6 │ │     0 _ => "Fizz"
                // 7 │ │     _ 0 => "Buzz"
                // 8 │ │     _ _ => num
                //   │ ╰──────────────^ `case` clauses have incompatible types
                // ```

                let prefix_source = {
                    let span = Span::new(start_line_span.start(), label.span.start());
                    self.source_slice(span, &tab).expect("prefix_source")
                };
                let highlighted_source = {
                    let span = Span::new(label.span.start(), start_line_span.end());
                    self.source_slice(span, &tab).expect("highlighted_source_1")
                };

                if prefix_source.trim().is_empty() {
                    // Section is prefixed by empty space, so we don't need to take
                    // up a new line.
                    //
                    // ```text
                    // 4 │ ╭     case (mod num 5) (mod num 3) of
                    // ```

                    // Write line number, border, and underline
                    Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineTopLeft::new(*mark_style).emit(writer, config)?;

                    // Write source line
                    write!(writer, " {}", prefix_source)?;
                    writer.set_color(&label_style)?;
                    write!(writer, "{}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;
                } else {
                    // There's source code in the prefix, so run an underline
                    // underneath it to get to the start of the span.
                    //
                    // ```text
                    // 4 │   fizz₁ num = case (mod num 5) (mod num 3) of
                    //   │ ╭─────────────^
                    // ```

                    // Write line number and border
                    Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;

                    // Write source line
                    write!(writer, "   {}", prefix_source)?;
                    writer.set_color(&label_style)?;
                    write!(writer, "{}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;

                    // Write border and underline
                    Gutter::new(None, gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineTop::new(*mark_style, &prefix_source).emit(writer, config)?;
                    NewLine::new().emit(writer, config)?;
                }

                // Write highlighted lines
                //
                // ```text
                // 5 │ │     0 0 => "FizzBuzz"
                // 6 │ │     0 _ => "Fizz"
                // 7 │ │     _ 0 => "Buzz"
                // ```
                for line_index in ((start.line.to_usize() + 1)..end.line.to_usize())
                    .map(|i| LineIndex::from(i as u32))
                {
                    let highlighted_source = {
                        let span = self.line_span(line_index).expect("highlighted_span");
                        self.source_slice(span, &tab).expect("highlighted_source_2")
                    };

                    // Write line number, border, and underline
                    Gutter::new(line_index.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineLeft::new(*mark_style).emit(writer, config)?;

                    // Write highlighted source
                    writer.set_color(label_style)?;
                    write!(writer, " {}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;
                }

                // Write last highlighted line
                //
                // ```text
                // 8 │ │     _ _ => num
                //   │ ╰──────────────^ `case` clauses have incompatible types
                // ```
                let highlighted_source = {
                    let span = Span::new(end_line_span.start(), label.span.end());
                    self.source_slice(span, &tab).expect("highlighted_source_3")
                };
                let suffix_source = {
                    let span = Span::new(label.span.end(), end_line_span.end());
                    self.source_slice(span, &tab).expect("suffix_source")
                };

                // Write line number, border, and underline
                Gutter::new(end.line.number(), gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                UnderlineLeft::new(*mark_style).emit(writer, config)?;

                // Write line source
                writer.set_color(label_style)?;
                write!(writer, " {}", highlighted_source)?;
                writer.reset()?;
                write!(writer, "{}", suffix_source.trim_end())?;
                NewLine::new().emit(writer, config)?;

                // Write border, underline, and label
                Gutter::new(None, gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                UnderlineBottom::new(*mark_style, &highlighted_source, &label.message)
                    .emit(writer, config)?;
                NewLine::new().emit(writer, config)?;
            }
        }

        // Write final border
        Gutter::new(None, gutter_padding).emit(writer, config)?;
        BorderLeft::new().emit(writer, config)?;
        NewLine::new().emit(writer, config)?;

        // Additional notes
        //
        // ```text
        // = expected type `Int`
        //      found type `String`
        // ```

        for note in self.notes {
            Note::new(gutter_padding, note).emit(writer, config)?;
        }

        Ok(())
    }
}
<commit_msg>Use `Span::merge`<commit_after>use codespan::{ByteIndex, FileId, Files, LineIndex, Location, Span};
use std::ffi::OsStr;
use std::io;
use termcolor::WriteColor;

use crate::diagnostic::Label;
use crate::term::Config;

use super::{Locus, NewLine};

mod border;
mod gutter;
mod note;
mod underline;

use self::border::{BorderLeft, BorderLeftBreak, BorderTop, BorderTopLeft};
use self::gutter::Gutter;
use self::note::Note;
use self::underline::{Underline, UnderlineBottom, UnderlineLeft, UnderlineTop, UnderlineTopLeft};

pub use self::underline::MarkStyle;

/// An underlined snippet of source code.
///
/// ```text
///   ┌── test:2:9 ───
///   │
/// 2 │ (+ test "")
///   │         ^^ expected `Int` but found `String`
///   │
///   = expected type `Int`
///        found type `String`
/// ```
pub struct SourceSnippet<'a, Source>
where
    Source: AsRef<str>,
{
    files: &'a Files<Source>,
    file_id: FileId,
    spans: Vec<(&'a Label, MarkStyle)>,
    notes: &'a [String],
}

impl<'a, Source> SourceSnippet<'a, Source>
where
    Source: AsRef<str>,
{
    pub fn new(
        files: &'a Files<Source>,
        file_id: FileId,
        spans: Vec<(&'a Label, MarkStyle)>,
        notes: &'a [String],
    ) -> Self {
        SourceSnippet {
            files,
            file_id,
            spans,
            notes,
        }
    }

    fn file_name(&self) -> &'a OsStr {
        self.files.name(self.file_id)
    }

    fn source_locus_spans(&self) -> (Span, Span) {
        let mut source_span = None;
        let mut locus_span = None;

        for (label, mark_style) in &self.spans {
            source_span =
                Some(source_span.map_or(label.span, |span| Span::merge(span, label.span)));
            if let MarkStyle::Primary(_) = mark_style {
                locus_span =
                    Some(locus_span.map_or(label.span, |span| Span::merge(span, label.span)));
            }
        }

        let source_span = source_span.unwrap_or(Span::initial());
        let locus_span = locus_span.unwrap_or(source_span);

        (source_span, locus_span)
    }

    fn location(&self, byte_index: ByteIndex) -> Result<Location, impl std::error::Error> {
        self.files.location(self.file_id, byte_index)
    }

    fn source_slice(&self, span: Span, tab: &'a str) -> Result<String, impl std::error::Error> {
        // NOTE: Not sure if we can do this more efficiently? Perhaps a custom
        // writer might be better?
        self.files
            .source_slice(self.file_id, span)
            .map(|s| s.replace('\t', tab))
    }

    fn line_span(&self, line_index: LineIndex) -> Result<Span, impl std::error::Error> {
        self.files.line_span(self.file_id, line_index)
    }

    pub fn emit(&self, writer: &mut (impl WriteColor + ?Sized), config: &Config) -> io::Result<()> {
        let (source_span, locus_span) = self.source_locus_spans();
        let locus_start = self.location(locus_span.start()).expect("locus_span_start");
        let source_end = self.location(source_span.end()).expect("source_span_end");

        // Use the length of the last line number as the gutter padding
        let gutter_padding = format!("{}", source_end.line.number()).len();
        // Cache the tabs we'll be using to pad the source strings.
        let tab = config.tab_padding();

        // Top left border and locus.
        //
        // ```text
        // ┌── test:2:9 ───
        // ```

        Gutter::new(None, gutter_padding).emit(writer, config)?;
        BorderTopLeft::new().emit(writer, config)?;
        BorderTop::new(2).emit(writer, config)?;
        write!(writer, " ")?;

        Locus::new(self.file_name(), locus_start).emit(writer, config)?;

        write!(writer, " ")?;
        BorderTop::new(3).emit(writer, config)?;
        NewLine::new().emit(writer, config)?;

        // TODO: Better grouping
        for (i, (label, mark_style)) in self.spans.iter().enumerate() {
            let start = self.location(label.span.start()).expect("location_start");
            let end = self.location(label.span.end()).expect("location_end");
            let start_line_span = self.line_span(start.line).expect("start_line_span");
            let end_line_span = self.line_span(end.line).expect("end_line_span");

            let label_style = mark_style.label_style(config);

            // Code snippet
            //
            // ```text
            //   │
            // 2 │ (+ test "")
            //   │         ^^ expected `Int` but found `String`
            //   │
            // ```

            // Write initial border
            Gutter::new(None, gutter_padding).emit(writer, config)?;
            match i {
                0 => BorderLeft::new().emit(writer, config)?,
                _ => BorderLeftBreak::new().emit(writer, config)?,
            }
            NewLine::new().emit(writer, config)?;

            // Write underlined source section
            if start.line == end.line {
                // Single line
                //
                // ```text
                // 2 │ (+ test "")
                //   │         ^^ expected `Int` but found `String`
                // ```

                let prefix_source = {
                    let span = Span::new(start_line_span.start(), label.span.start());
                    self.source_slice(span, &tab).expect("prefix_source")
                };
                let highlighted_source = {
                    let span = label.span;
                    self.source_slice(span, &tab).expect("highlighted_source")
                };
                let suffix_source = {
                    let span = Span::new(label.span.end(), end_line_span.end());
                    self.source_slice(span, &tab).expect("suffix_source")
                };

                // Write line number and border
                Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;

                // Write line source
                write!(writer, " {}", prefix_source)?;
                writer.set_color(label_style)?;
                write!(writer, "{}", highlighted_source)?;
                writer.reset()?;
                write!(writer, "{}", suffix_source.trim_end())?;
                NewLine::new().emit(writer, config)?;

                // Write border, underline, and label
                Gutter::new(None, gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                Underline::new(
                    *mark_style,
                    &prefix_source,
                    &highlighted_source,
                    &label.message,
                )
                .emit(writer, config)?;
                NewLine::new().emit(writer, config)?;
            } else {
                // Multiple lines
                //
                // ```text
                // 4 │   fizz₁ num = case (mod num 5) (mod num 3) of
                //   │ ╭─────────────^
                // 5 │ │     0 0 => "FizzBuzz"
                // 6 │ │     0 _ => "Fizz"
                // 7 │ │     _ 0 => "Buzz"
                // 8 │ │     _ _ => num
                //   │ ╰──────────────^ `case` clauses have incompatible types
                // ```

                let prefix_source = {
                    let span = Span::new(start_line_span.start(), label.span.start());
                    self.source_slice(span, &tab).expect("prefix_source")
                };
                let highlighted_source = {
                    let span = Span::new(label.span.start(), start_line_span.end());
                    self.source_slice(span, &tab).expect("highlighted_source_1")
                };

                if prefix_source.trim().is_empty() {
                    // Section is prefixed by empty space, so we don't need to take
                    // up a new line.
                    //
                    // ```text
                    // 4 │ ╭     case (mod num 5) (mod num 3) of
                    // ```

                    // Write line number, border, and underline
                    Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineTopLeft::new(*mark_style).emit(writer, config)?;

                    // Write source line
                    write!(writer, " {}", prefix_source)?;
                    writer.set_color(&label_style)?;
                    write!(writer, "{}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;
                } else {
                    // There's source code in the prefix, so run an underline
                    // underneath it to get to the start of the span.
                    //
                    // ```text
                    // 4 │   fizz₁ num = case (mod num 5) (mod num 3) of
                    //   │ ╭─────────────^
                    // ```

                    // Write line number and border
                    Gutter::new(start.line.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;

                    // Write source line
                    write!(writer, "   {}", prefix_source)?;
                    writer.set_color(&label_style)?;
                    write!(writer, "{}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;

                    // Write border and underline
                    Gutter::new(None, gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineTop::new(*mark_style, &prefix_source).emit(writer, config)?;
                    NewLine::new().emit(writer, config)?;
                }

                // Write highlighted lines
                //
                // ```text
                // 5 │ │     0 0 => "FizzBuzz"
                // 6 │ │     0 _ => "Fizz"
                // 7 │ │     _ 0 => "Buzz"
                // ```
                for line_index in ((start.line.to_usize() + 1)..end.line.to_usize())
                    .map(|i| LineIndex::from(i as u32))
                {
                    let highlighted_source = {
                        let span = self.line_span(line_index).expect("highlighted_span");
                        self.source_slice(span, &tab).expect("highlighted_source_2")
                    };

                    // Write line number, border, and underline
                    Gutter::new(line_index.number(), gutter_padding).emit(writer, config)?;
                    BorderLeft::new().emit(writer, config)?;
                    UnderlineLeft::new(*mark_style).emit(writer, config)?;

                    // Write highlighted source
                    writer.set_color(label_style)?;
                    write!(writer, " {}", highlighted_source.trim_end())?;
                    writer.reset()?;
                    NewLine::new().emit(writer, config)?;
                }

                // Write last highlighted line
                //
                // ```text
                // 8 │ │     _ _ => num
                //   │ ╰──────────────^ `case` clauses have incompatible types
                // ```
                let highlighted_source = {
                    let span = Span::new(end_line_span.start(), label.span.end());
                    self.source_slice(span, &tab).expect("highlighted_source_3")
                };
                let suffix_source = {
                    let span = Span::new(label.span.end(), end_line_span.end());
                    self.source_slice(span, &tab).expect("suffix_source")
                };

                // Write line number, border, and underline
                Gutter::new(end.line.number(), gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                UnderlineLeft::new(*mark_style).emit(writer, config)?;

                // Write line source
                writer.set_color(label_style)?;
                write!(writer, " {}", highlighted_source)?;
                writer.reset()?;
                write!(writer, "{}", suffix_source.trim_end())?;
                NewLine::new().emit(writer, config)?;

                // Write border, underline, and label
                Gutter::new(None, gutter_padding).emit(writer, config)?;
                BorderLeft::new().emit(writer, config)?;
                UnderlineBottom::new(*mark_style, &highlighted_source, &label.message)
                    .emit(writer, config)?;
                NewLine::new().emit(writer, config)?;
            }
        }

        // Write final border
        Gutter::new(None, gutter_padding).emit(writer, config)?;
        BorderLeft::new().emit(writer, config)?;
        NewLine::new().emit(writer, config)?;

        // Additional notes
        //
        // ```text
        // = expected type `Int`
        //      found type `String`
        // ```

        for note in self.notes {
            Note::new(gutter_padding, note).emit(writer, config)?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use background_hang_monitor::HangMonitorRegister;
use ipc_channel::ipc;
use msg::constellation_msg::ScriptHangAnnotation;
use msg::constellation_msg::TEST_PIPELINE_ID;
use msg::constellation_msg::{HangAlert, HangAnnotation};
use msg::constellation_msg::{MonitoredComponentId, MonitoredComponentType};
use std::thread;
use std::time::Duration;

#[test]
fn test_hang_monitoring() {
    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone());
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangAlert::Transient(component_id, _annotation) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        HangAlert::Permanent(..) => unreachable!(),
    }

    // Sleep until the "permanent" timeout has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Check for a permanent hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangAlert::Permanent(component_id, _annotation, _profile) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        HangAlert::Transient(..) => unreachable!(),
    }

    // Now the component is not hanging anymore.
    background_hang_monitor.notify_activity(hang_annotation);
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangAlert::Transient(component_id, _annotation) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        HangAlert::Permanent(..) => unreachable!(),
    }

    // Now the component is waiting for a new task.
    background_hang_monitor.notify_wait();

    // Sleep for a while.
    thread::sleep(Duration::from_millis(100));

    // The component is still waiting, but not hanging.
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // New task handling starts.
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // We're getting new hang alerts for the latest task.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangAlert::Transient(component_id, _annotation) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        HangAlert::Permanent(..) => unreachable!(),
    }

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Shut-down the hang monitor
    drop(background_hang_monitor_register);
    drop(background_hang_monitor);

    // Sleep until the "max-timeout" has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Still no new alerts because the hang monitor has shut-down already.
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}

#[test]
fn test_hang_monitoring_unregister() {
    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone());
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Unregister the component.
    background_hang_monitor.unregister();

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}
<commit_msg>Add unit test for sampling profiler.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use background_hang_monitor::HangMonitorRegister;
use ipc_channel::ipc;
use msg::constellation_msg::ScriptHangAnnotation;
use msg::constellation_msg::TEST_PIPELINE_ID;
use msg::constellation_msg::{HangAlert, HangAnnotation, HangMonitorAlert};
use msg::constellation_msg::{MonitoredComponentId, MonitoredComponentType};
use std::thread;
use std::time::Duration;

#[test]
#[cfg(target_os = "macos")]
fn test_sampler() {
    use msg::constellation_msg::SamplerControlMsg;
    use serde_json::Value;

    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let _background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    const RATE: u64 = 10;
    sampler_sender
        .send(SamplerControlMsg::Enable(Duration::from_millis(RATE)))
        .unwrap();

    thread::sleep(Duration::from_millis(30));

    sampler_sender.send(SamplerControlMsg::Disable).unwrap();

    loop {
        match background_hang_monitor_receiver.recv().unwrap() {
            HangMonitorAlert::Hang(_) => continue,
            HangMonitorAlert::Profile(ref bytes) => {
                let json: Value = serde_json::from_slice(bytes).unwrap();
                let rate = json["rate"].as_u64().unwrap();
                assert_eq!(rate, RATE);
                let data = json["data"].as_array().unwrap();
                assert!(data.len() > 1);
                assert_eq!(data[0]["name"].as_str().unwrap(), "test_sampler");
                assert!(data[0]["frames"].as_array().unwrap().len() > 0);
                break;
            },
        }
    }
}

#[test]
fn test_hang_monitoring() {
    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Sleep until the "permanent" timeout has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Check for a permanent hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Permanent(component_id, _annotation, _profile)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is not hanging anymore.
    background_hang_monitor.notify_activity(hang_annotation);
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // Check for a transient hang alert.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // Now the component is waiting for a new task.
    background_hang_monitor.notify_wait();

    // Sleep for a while.
    thread::sleep(Duration::from_millis(100));

    // The component is still waiting, but not hanging.
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // New task handling starts.
    background_hang_monitor.notify_activity(hang_annotation);

    // Sleep for a while.
    thread::sleep(Duration::from_millis(10));

    // We're getting new hang alerts for the latest task.
    match background_hang_monitor_receiver.recv().unwrap() {
        HangMonitorAlert::Hang(HangAlert::Transient(component_id, _annotation)) => {
            let expected = MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script);
            assert_eq!(expected, component_id);
        },
        _ => unreachable!(),
    }

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());

    // Shut-down the hang monitor
    drop(background_hang_monitor_register);
    drop(background_hang_monitor);

    // Sleep until the "max-timeout" has been reached.
    thread::sleep(Duration::from_millis(1000));

    // Still no new alerts because the hang monitor has shut-down already.
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}

#[test]
fn test_hang_monitoring_unregister() {
    let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
        ipc::channel().expect("ipc channel failure");
    let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");

    let background_hang_monitor_register =
        HangMonitorRegister::init(background_hang_monitor_ipc_sender.clone(), sampler_receiver);
    let background_hang_monitor = background_hang_monitor_register.register_component(
        MonitoredComponentId(TEST_PIPELINE_ID, MonitoredComponentType::Script),
        Duration::from_millis(10),
        Duration::from_millis(1000),
    );

    // Start an activity.
    let hang_annotation = HangAnnotation::Script(ScriptHangAnnotation::AttachLayout);
    background_hang_monitor.notify_activity(hang_annotation);

    // Unregister the component.
    background_hang_monitor.unregister();

    // Sleep until the "transient" timeout has been reached.
    thread::sleep(Duration::from_millis(10));

    // No new alert yet
    assert!(background_hang_monitor_receiver.try_recv().is_err());
}
<|endoftext|>