<commit_before>use super::{SpecifierClass, SpecifierStack, WebsocatConfiguration2};
use std::rc::Rc;
use std::str::FromStr;

#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
pub enum StdioUsageStatus {
    /// Does not use standard input or output at all
    None,
    /// Uses a reuser for connecting multiple peers at stdio, not distinguishing between IsItself and Indirectly
    WithReuser,
    /// Stdio wrapped into something (but not the reuser)
    Indirectly,
    /// Is the `-` or `stdio:` or `threadedstdio:` itself.
    IsItself,
}

trait ClassExt {
    fn is_stdio(&self) -> bool;
    fn is_reuser(&self) -> bool;
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl ClassExt for Rc<SpecifierClass> {
    fn is_stdio(&self) -> bool {
        [
            "StdioClass",
            "ThreadedStdioClass",
            "ThreadedStdioSubstituteClass",
        ].contains(&self.get_name())
    }
    fn is_reuser(&self) -> bool {
        [
            "ReuserClass",
            "BroadcastReuserClass",
        ].contains(&self.get_name())
    }
}

pub trait SpecifierStackExt {
    fn stdio_usage_status(&self) -> StdioUsageStatus;
    fn reuser_count(&self) -> usize;
    fn contains(&self, t: &'static str) -> bool;
    fn is_multiconnect(&self) -> bool;
    fn is_stream_oriented(&self) -> bool;
    fn insert_line_class_in_proper_place(&mut self, x: Rc<SpecifierClass>);
}
impl SpecifierStackExt for SpecifierStack {
    fn stdio_usage_status(&self) -> StdioUsageStatus {
        use self::StdioUsageStatus::*;

        if !self.addrtype.is_stdio() {
            return None;
        }

        let mut sus: StdioUsageStatus = IsItself;

        for overlay in self.overlays.iter().rev() {
            if overlay.is_reuser() {
                sus = WithReuser;
            } else if sus == IsItself {
                sus = Indirectly;
            }
        }
        sus
    }
    fn reuser_count(&self) -> usize {
        let mut c = 0;
        for overlay in &self.overlays {
            if overlay.is_reuser() {
                c += 1;
            }
        }
        c
    }
    fn contains(&self, t: &'static str) -> bool {
        for overlay in &self.overlays {
            if overlay.get_name() == t {
                return true;
            }
        }
        self.addrtype.get_name() == t
    }
    fn is_multiconnect(&self) -> bool {
        use super::ClassMulticonnectStatus::*;
        match self.addrtype.multiconnect_status() {
            MultiConnect => (),
            SingleConnect => return false,
            MulticonnectnessDependsOnInnerType => unreachable!(),
        }
        for overlay in self.overlays.iter().rev() {
            match overlay.multiconnect_status() {
                MultiConnect => (),
                SingleConnect => return false,
                MulticonnectnessDependsOnInnerType => (),
            }
        }
        true
    }
    fn is_stream_oriented(&self) -> bool {
        use super::ClassMessageBoundaryStatus::*;
        let mut q = match self.addrtype.message_boundary_status() {
            StreamOriented => true,
            MessageOriented => false,
            MessageBoundaryStatusDependsOnInnerType => unreachable!(),
        };
        for overlay in self.overlays.iter().rev() {
            match overlay.message_boundary_status() {
                StreamOriented => q = true,
                MessageOriented => q = false,
                MessageBoundaryStatusDependsOnInnerType => (),
            }
        }
        q
    }
    fn insert_line_class_in_proper_place(&mut self, x: Rc<SpecifierClass>) {
        use super::ClassMessageBoundaryStatus::*;
        let mut insert_idx = 0;
        for overlay in &self.overlays {
            match overlay.message_boundary_status() {
                StreamOriented => break,
                MessageOriented => break,
                MessageBoundaryStatusDependsOnInnerType => insert_idx += 1,
            }
        }
        self.overlays.insert(insert_idx, x);
    }
}

impl WebsocatConfiguration2 {
    pub fn inetd_mode(&self) -> bool {
        self.contains_class("InetdClass")
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[cfg_attr(feature="cargo-clippy", allow(nonminimal_bool))]
    pub fn websocket_used(&self) -> bool {
        false
        || self.contains_class("WsConnectClass")
        || self.contains_class("WsClientClass")
        || self.contains_class("WsClientSecureClass")
        || self.contains_class("WsServerClass")
    }

    pub fn contains_class(&self, x: &'static str) -> bool {
        self.s1.contains(x) || self.s2.contains(x)
    }

    pub fn get_exec_parameter(&self) -> Option<&str> {
        if self.s1.addrtype.get_name() == "ExecClass" {
            return Some(self.s1.addr.as_str());
        }
        if self.s2.addrtype.get_name() == "ExecClass" {
            return Some(self.s2.addr.as_str());
        }
        None
    }

    pub fn lint_and_fixup<F>(&mut self, on_warning: &F) -> super::Result<()>
    where
        F: for<'a> Fn(&'a str) -> () + 'static,
    {
        let mut reuser_has_been_inserted = false;
        let multiconnect = !self.opts.oneshot && self.s1.is_multiconnect();
        use self::StdioUsageStatus::{Indirectly, IsItself, None, WithReuser};
        match (self.s1.stdio_usage_status(), self.s2.stdio_usage_status()) {
            (_, None) => (),
            (None, WithReuser) => (),
            (None, IsItself) | (None, Indirectly) => {
                if multiconnect {
                    self.s2.overlays.insert(
                        0,
                        Rc::new(super::broadcast_reuse_peer::BroadcastReuserClass),
                    );
                    reuser_has_been_inserted = true;
                }
            }
            (IsItself, IsItself) => {
                info!("Special mode, expection from usual one-stdio rule. Acting like `cat(1)`");
                self.s2 = SpecifierStack::from_str("mirror:")?;
                if self.opts.unidirectional ^ self.opts.unidirectional_reverse {
                    self.opts.unidirectional = false;
                    self.opts.unidirectional_reverse = false;
                }
                return Ok(());
            }
            (_, _) => {
                Err("Too many usages of stdin/stdout. Specify it either on left or right address, not on both.")?;
            }
        }

        if self.s1.reuser_count() + self.s2.reuser_count() > 1 {
            if reuser_has_been_inserted {
                error!("The reuser you specified conflicts with automatically inserted reuser based on usage of stdin/stdout in multiconnect mode.");
            }
            Err("Too many usages of connection reuser. Please limit to only one instance.")?;
        }

        if !self.opts.no_auto_linemode && self.opts.websocket_text_mode {
            match (self.s1.is_stream_oriented(), self.s2.is_stream_oriented()) {
                (false, false) => {}
                (true, true) => {}
                (true, false) => {
                    info!("Auto-inserting the line mode");
                    self.s1.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Line2MessageClass,
                    ));
                    self.s2.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Message2LineClass,
                    ));
                }
                (false, true) => {
                    info!("Auto-inserting the line mode");
                    self.s2.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Line2MessageClass,
                    ));
                    self.s1.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Message2LineClass,
                    ));
                }
            }
        }

        if !self.opts.oneshot && self.s2.is_multiconnect() && !self.s1.is_multiconnect() {
            on_warning("You have specified a listener on the right (as the second positional argument) instead of on the left. It will only serve one connection.\nChange arguments order to enable multiple parallel connections or use --oneshot argument to make single connection explicit.");
        }

        if multiconnect
            && (self.s2.addrtype.get_name() == "WriteFileClass"
                || self.s2.addrtype.get_name() == "AppendFileClass")
            && self.s2.reuser_count() == 0
        {
            info!("Auto-inserting the reuser");
            self.s2
                .overlays
                .push(Rc::new(super::primitive_reuse_peer::ReuserClass));
        }

        if self.s1.addrtype.get_name() == "ExecClass" && self.s2.addrtype.get_name() == "ExecClass"
        {
            Err("Can't use exec: more than one time. Replace one of them with sh-c: or cmd:.")?;
        }

        if let Some(x) = self.get_exec_parameter() {
            if self.opts.exec_args.is_empty() && x.contains(' ') {
                on_warning("Warning: you specified exec: without the corresponding --exec-args at the end of command line. Unlike in cmd: or sh-c:, spaces inside exec:'s direct parameter are interpreted as part of program name, not as separator.");
            }
        }

        if self.opts.restrict_uri.is_some() && !self.contains_class("WsServerClass") {
            on_warning("--restrict-uri is meaningless without a WebSocket server");
        }

        if !self.opts.serve_static_files.is_empty() && !self.contains_class("WsServerClass") {
            on_warning("--static-file (-F) is meaningless without a WebSocket server");
        }

        for sf in &self.opts.serve_static_files {
            if !sf.uri.starts_with('/') {
                on_warning(&format!("Static file's URI `{}` should begin with `/`?", sf.uri));
            }
            if !sf.file.exists() {
                on_warning(&format!("File {:?} does not exist", sf.file));
            }
            if !sf.content_type.contains('/') {
                on_warning(&format!("Content-Type `{}` lacks `/` character",
                    sf.content_type));
            }
        }

        // TODO: UDP connect oneshot mode

        // TODO: tests for the linter
        Ok(())
    }
}
<commit_msg>Lints about --set-environment<commit_after>use super::{SpecifierClass, SpecifierStack, WebsocatConfiguration2};
use std::rc::Rc;
use std::str::FromStr;

#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
pub enum StdioUsageStatus {
    /// Does not use standard input or output at all
    None,
    /// Uses a reuser for connecting multiple peers at stdio, not distinguishing between IsItself and Indirectly
    WithReuser,
    /// Stdio wrapped into something (but not the reuser)
    Indirectly,
    /// Is the `-` or `stdio:` or `threadedstdio:` itself.
    IsItself,
}

trait ClassExt {
    fn is_stdio(&self) -> bool;
    fn is_reuser(&self) -> bool;
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl ClassExt for Rc<SpecifierClass> {
    fn is_stdio(&self) -> bool {
        [
            "StdioClass",
            "ThreadedStdioClass",
            "ThreadedStdioSubstituteClass",
        ].contains(&self.get_name())
    }
    fn is_reuser(&self) -> bool {
        [
            "ReuserClass",
            "BroadcastReuserClass",
        ].contains(&self.get_name())
    }
}

pub trait SpecifierStackExt {
    fn stdio_usage_status(&self) -> StdioUsageStatus;
    fn reuser_count(&self) -> usize;
    fn contains(&self, t: &'static str) -> bool;
    fn is_multiconnect(&self) -> bool;
    fn is_stream_oriented(&self) -> bool;
    fn insert_line_class_in_proper_place(&mut self, x: Rc<SpecifierClass>);
}
impl SpecifierStackExt for SpecifierStack {
    fn stdio_usage_status(&self) -> StdioUsageStatus {
        use self::StdioUsageStatus::*;

        if !self.addrtype.is_stdio() {
            return None;
        }

        let mut sus: StdioUsageStatus = IsItself;

        for overlay in self.overlays.iter().rev() {
            if overlay.is_reuser() {
                sus = WithReuser;
            } else if sus == IsItself {
                sus = Indirectly;
            }
        }
        sus
    }
    fn reuser_count(&self) -> usize {
        let mut c = 0;
        for overlay in &self.overlays {
            if overlay.is_reuser() {
                c += 1;
            }
        }
        c
    }
    fn contains(&self, t: &'static str) -> bool {
        for overlay in &self.overlays {
            if overlay.get_name() == t {
                return true;
            }
        }
        self.addrtype.get_name() == t
    }
    fn is_multiconnect(&self) -> bool {
        use super::ClassMulticonnectStatus::*;
        match self.addrtype.multiconnect_status() {
            MultiConnect => (),
            SingleConnect => return false,
            MulticonnectnessDependsOnInnerType => unreachable!(),
        }
        for overlay in self.overlays.iter().rev() {
            match overlay.multiconnect_status() {
                MultiConnect => (),
                SingleConnect => return false,
                MulticonnectnessDependsOnInnerType => (),
            }
        }
        true
    }
    fn is_stream_oriented(&self) -> bool {
        use super::ClassMessageBoundaryStatus::*;
        let mut q = match self.addrtype.message_boundary_status() {
            StreamOriented => true,
            MessageOriented => false,
            MessageBoundaryStatusDependsOnInnerType => unreachable!(),
        };
        for overlay in self.overlays.iter().rev() {
            match overlay.message_boundary_status() {
                StreamOriented => q = true,
                MessageOriented => q = false,
                MessageBoundaryStatusDependsOnInnerType => (),
            }
        }
        q
    }
    fn insert_line_class_in_proper_place(&mut self, x: Rc<SpecifierClass>) {
        use super::ClassMessageBoundaryStatus::*;
        let mut insert_idx = 0;
        for overlay in &self.overlays {
            match overlay.message_boundary_status() {
                StreamOriented => break,
                MessageOriented => break,
                MessageBoundaryStatusDependsOnInnerType => insert_idx += 1,
            }
        }
        self.overlays.insert(insert_idx, x);
    }
}

impl WebsocatConfiguration2 {
    pub fn inetd_mode(&self) -> bool {
        self.contains_class("InetdClass")
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[cfg_attr(feature="cargo-clippy", allow(nonminimal_bool))]
    pub fn websocket_used(&self) -> bool {
        false
        || self.contains_class("WsConnectClass")
        || self.contains_class("WsClientClass")
        || self.contains_class("WsClientSecureClass")
        || self.contains_class("WsServerClass")
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[cfg_attr(feature="cargo-clippy", allow(nonminimal_bool))]
    pub fn exec_used(&self) -> bool {
        false
        || self.contains_class("ExecClass")
        || self.contains_class("CmdClass")
        || self.contains_class("ShCClass")
    }

    pub fn contains_class(&self, x: &'static str) -> bool {
        self.s1.contains(x) || self.s2.contains(x)
    }

    pub fn get_exec_parameter(&self) -> Option<&str> {
        if self.s1.addrtype.get_name() == "ExecClass" {
            return Some(self.s1.addr.as_str());
        }
        if self.s2.addrtype.get_name() == "ExecClass" {
            return Some(self.s2.addr.as_str());
        }
        None
    }

    pub fn lint_and_fixup<F>(&mut self, on_warning: &F) -> super::Result<()>
    where
        F: for<'a> Fn(&'a str) -> () + 'static,
    {
        let mut reuser_has_been_inserted = false;
        let multiconnect = !self.opts.oneshot && self.s1.is_multiconnect();
        use self::StdioUsageStatus::{Indirectly, IsItself, None, WithReuser};
        match (self.s1.stdio_usage_status(), self.s2.stdio_usage_status()) {
            (_, None) => (),
            (None, WithReuser) => (),
            (None, IsItself) | (None, Indirectly) => {
                if multiconnect {
                    self.s2.overlays.insert(
                        0,
                        Rc::new(super::broadcast_reuse_peer::BroadcastReuserClass),
                    );
                    reuser_has_been_inserted = true;
                }
            }
            (IsItself, IsItself) => {
                info!("Special mode, expection from usual one-stdio rule. Acting like `cat(1)`");
                self.s2 = SpecifierStack::from_str("mirror:")?;
                if self.opts.unidirectional ^ self.opts.unidirectional_reverse {
                    self.opts.unidirectional = false;
                    self.opts.unidirectional_reverse = false;
                }
                return Ok(());
            }
            (_, _) => {
                Err("Too many usages of stdin/stdout. Specify it either on left or right address, not on both.")?;
            }
        }

        if self.s1.reuser_count() + self.s2.reuser_count() > 1 {
            if reuser_has_been_inserted {
                error!("The reuser you specified conflicts with automatically inserted reuser based on usage of stdin/stdout in multiconnect mode.");
            }
            Err("Too many usages of connection reuser. Please limit to only one instance.")?;
        }

        if !self.opts.no_auto_linemode && self.opts.websocket_text_mode {
            match (self.s1.is_stream_oriented(), self.s2.is_stream_oriented()) {
                (false, false) => {}
                (true, true) => {}
                (true, false) => {
                    info!("Auto-inserting the line mode");
                    self.s1.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Line2MessageClass,
                    ));
                    self.s2.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Message2LineClass,
                    ));
                }
                (false, true) => {
                    info!("Auto-inserting the line mode");
                    self.s2.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Line2MessageClass,
                    ));
                    self.s1.insert_line_class_in_proper_place(Rc::new(
                        super::line_peer::Message2LineClass,
                    ));
                }
            }
        }

        if !self.opts.oneshot && self.s2.is_multiconnect() && !self.s1.is_multiconnect() {
            on_warning("You have specified a listener on the right (as the second positional argument) instead of on the left. It will only serve one connection.\nChange arguments order to enable multiple parallel connections or use --oneshot argument to make single connection explicit.");
        }

        if multiconnect
            && (self.s2.addrtype.get_name() == "WriteFileClass"
                || self.s2.addrtype.get_name() == "AppendFileClass")
            && self.s2.reuser_count() == 0
        {
            info!("Auto-inserting the reuser");
            self.s2
                .overlays
                .push(Rc::new(super::primitive_reuse_peer::ReuserClass));
        }

        if self.s1.addrtype.get_name() == "ExecClass" && self.s2.addrtype.get_name() == "ExecClass"
        {
            Err("Can't use exec: more than one time. Replace one of them with sh-c: or cmd:.")?;
        }

        if let Some(x) = self.get_exec_parameter() {
            if self.opts.exec_args.is_empty() && x.contains(' ') {
                on_warning("Warning: you specified exec: without the corresponding --exec-args at the end of command line. Unlike in cmd: or sh-c:, spaces inside exec:'s direct parameter are interpreted as part of program name, not as separator.");
            }
        }

        if self.opts.restrict_uri.is_some() && !self.contains_class("WsServerClass") {
            on_warning("--restrict-uri is meaningless without a WebSocket server");
        }

        if !self.opts.serve_static_files.is_empty() && !self.contains_class("WsServerClass") {
            on_warning("--static-file (-F) is meaningless without a WebSocket server");
        }

        for sf in &self.opts.serve_static_files {
            if !sf.uri.starts_with('/') {
                on_warning(&format!("Static file's URI `{}` should begin with `/`?", sf.uri));
            }
            if !sf.file.exists() {
                on_warning(&format!("File {:?} does not exist", sf.file));
            }
            if !sf.content_type.contains('/') {
                on_warning(&format!("Content-Type `{}` lacks `/` character",
                    sf.content_type));
            }
        }

        if self.opts.exec_set_env {
            if !self.exec_used() {
                on_warning("-e (--set-environment) is meaningless without a exec: or sh-c: or cmd: address");
            }
            if !self.contains_class("TcpListenClass") && !self.contains_class("WsServerClass") {
                on_warning("-e (--set-environment) is currently meaningless without a websocket server and/or TCP listener");
            }
        }

        // TODO: UDP connect oneshot mode

        // TODO: tests for the linter
        Ok(())
    }
}
<|endoftext|>


<commit_before>use libc;

use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window = c_int;
type Xdo = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_down(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_up(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7,
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64,
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY,
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(format!("U{:X}", c as u32));
    }
    #[allow(deprecated)]
    // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "BackSpace",
        Key::CapsLock => "CapsLock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "Down",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "PageDown",
        Key::PageUp => "PageUp",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command | Key::Super | Key::Windows | Key::Meta => "Meta",
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
}
<commit_msg>Use correct keycodes for PageUp & PageDown<commit_after>use libc;

use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window = c_int;
type Xdo = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_down(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_up(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7,
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64,
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY,
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(format!("U{:X}", c as u32));
    }
    #[allow(deprecated)]
    // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "BackSpace",
        Key::CapsLock => "CapsLock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "Down",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "Page_Down",
        Key::PageUp => "Page_Up",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command | Key::Super | Key::Windows | Key::Meta => "Meta",
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // try a pending dispatch
        // TODO: insert a non-blocking read from socket, overwise no new events will ever come
        {
            self.ctxt.dispatch_pending();
            let mut guard = self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                let mut guard = self.evq.lock().unwrap().dispatch_pending();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front();
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.set_title(title.into())
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        Some(self.size.lock().unwrap().clone())
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let (w, h) = self.size.lock().unwrap().clone();
        let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
        Some((w as u32, h as u32))
    }

    #[inline]
    // NOTE: This will only resize the borders, the contents must be updated by the user
    pub fn set_inner_size(&self, x: u32, y: u32) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.resize(x as i32, y as i32);
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<commit_msg>wayland: Implement wakeup_event_loop()<commit_after>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy {
    ctxt: Arc<WaylandContext>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        // Send a sync event, so that any waiting "dispatch" will return
        self.ctxt.display.sync();
        self.eviter.lock().unwrap().push_back(Event::Awakened);
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // try a pending dispatch
        // TODO: insert a non-blocking read from socket, overwise no new events will ever come
        {
            self.ctxt.dispatch_pending();
            let mut guard = self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                let mut guard = self.evq.lock().unwrap().dispatch_pending();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front();
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.set_title(title.into())
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        Some(self.size.lock().unwrap().clone())
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let (w, h) = self.size.lock().unwrap().clone();
        let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
        Some((w as u32, h as u32))
    }

    #[inline]
    // NOTE: This will only resize the borders, the contents must be updated by the user
    pub fn set_inner_size(&self, x: u32, y: u32) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.resize(x as i32, y as i32);
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy {
            ctxt: self.ctxt.clone(),
            eviter: self.eviter.clone()
        }
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate itertools;

use std::collections::HashMap;

use self::itertools::Itertools;
use self::rustc_serialize::json;

use ngrams::ngrams;

pub struct Model {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Model {
    pub fn build_from_text(text: &str) -> Model {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                // If you don't want to unecessarily allocate strings, this is
                // the only way to do it. This RFC should fix this if it ever
                // gets accepted: // https://github.com/rust-lang/rfcs/pull/1533
                if let Some(count) = ngram_counts.get_mut(ngram) {
                    *count += 1;
                    continue;
                }
                ngram_counts.insert(ngram.to_owned(), 1);
            }
        }

        let ngrams = ngram_counts
            .into_iter()
            .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
            .into_iter()
            .take(300)  // Models need to have the same size, or have normalized "differences"
            .map(|(ngram, _count)| ngram);

        // Nicer way to build a hash map.
        Model { ngram_ranks: ngrams.enumerate().map(|(a, b)| (b, a)).collect() }
    }

    pub fn deserialize(bytes: Vec<u8>) -> Model {
        let string = String::from_utf8(bytes).unwrap();
        let ngram_ranks = json::decode(string.as_str()).unwrap();
        Model { ngram_ranks: ngram_ranks }
    }

    pub fn serialize(&self) -> Vec<u8> {
        json::encode(&self.ngram_ranks).unwrap().into_bytes()
    }

    pub fn compare(&self, other: &Model) -> usize {
        let max_difference = other.ngram_ranks.len();
        let mut difference = 0;
        for (ngram, rank) in &self.ngram_ranks {
            difference += match other.ngram_ranks.get(ngram) {
                Some(other_rank) => get_difference(*rank, *other_rank),
                None => max_difference,
            }
        }
        difference
    }
}

fn get_difference(a: usize, b: usize) -> usize {
    if a > b { a - b } else { b - a }
}
<commit_msg>Split the incoming text into words before generating ngrams<commit_after>extern crate rustc_serialize;
extern crate itertools;

use std::collections::HashMap;

use self::itertools::Itertools;
use self::rustc_serialize::json;

use ngrams::ngrams;

pub struct Model {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Model {
    pub fn build_from_text(text: &str) -> Model {
        let mut ngram_counts = HashMap::new();
        let words = text.split(|ch: char| !ch.is_alphabetic()).filter(|s| !s.is_empty());
        for word in words {
            for n in 1..6 {
                for ngram in ngrams(word, n) {
                    // If you don't want to unecessarily allocate strings, this is
                    // the only way to do it. This RFC should fix this if it ever
                    // gets accepted: // https://github.com/rust-lang/rfcs/pull/1533
                    if let Some(count) = ngram_counts.get_mut(ngram) {
                        *count += 1;
                        continue;
                    }
                    ngram_counts.insert(ngram.to_owned(), 1);
                }
            }
        }

        let ngrams = ngram_counts
            .into_iter()
            .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
            .into_iter()
            .take(300)  // Models need to have the same size, or have normalized "differences"
            .map(|(ngram, _count)| ngram);

        // Nicer way to build a hash map.
        Model { ngram_ranks: ngrams.enumerate().map(|(a, b)| (b, a)).collect() }
    }

    pub fn deserialize(bytes: Vec<u8>) -> Model {
        let string = String::from_utf8(bytes).unwrap();
        let ngram_ranks = json::decode(string.as_str()).unwrap();
        Model { ngram_ranks: ngram_ranks }
    }

    pub fn serialize(&self) -> Vec<u8> {
        json::encode(&self.ngram_ranks).unwrap().into_bytes()
    }

    pub fn compare(&self, other: &Model) -> usize {
        let max_difference = other.ngram_ranks.len();
        let mut difference = 0;
        for (ngram, rank) in &self.ngram_ranks {
            difference += match other.ngram_ranks.get(ngram) {
                Some(other_rank) => get_difference(*rank, *other_rank),
                None => max_difference,
            }
        }
        difference
    }
}

fn get_difference(a: usize, b: usize) -> usize {
    if a > b { a - b } else { b - a }
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error;
use std::fmt;
use std::env;
use std;

use super::imp;
use super::util;

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

/// Error returned when persisting a temporary file fails
#[derive(Debug)]
pub struct PersistError {
    /// The underlying IO error.
    pub error: io::Error,
    /// The temporary file that couldn't be persisted.
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    #[inline]
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl fmt::Display for PersistError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    #[inline]
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    #[inline]
    fn inner(&self) -> &NamedTempFileInner {
        self.0.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut NamedTempFileInner {
        self.0.as_mut().unwrap()
    }

    /// Create a new temporary file.
    #[inline]
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        loop {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
    }

    /// Queries metadata about the underlying file.
    #[inline]
    pub fn metadata(&self) -> io::Result<fs::Metadata> {
        self.inner().file.metadata()
    }

    /// Truncate the file to `size` bytes.
    #[inline]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.inner().file.set_len(size)
    }

    /// Get the temporary file's path.
    #[inline]
    pub fn path(&self) -> &Path {
        &self.inner().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    #[inline]
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    ///
    /// Note: Temporary files cannot be persisted across filesystems.
    #[inline]
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match fs::rename(&self.inner().path, new_path) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    #[inline]
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_mut().file.read(buf)
    }
}

impl Write for NamedTempFile {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner_mut().file.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.inner_mut().file.flush()
    }
}

impl Seek for NamedTempFile {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.inner_mut().file.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.inner().file.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.inner().file.as_raw_handle()
    }
}
<commit_msg>Verbose security warnings.<commit_after>use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error;
use std::fmt;
use std::env;
use std;

use super::imp;
use super::util;

/// A named temporary file.
///
/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
///
/// NamedTempFiles are deleted on drop. As rust doesn't guarantee that a struct will ever be
/// dropped, these temporary files will not be deleted on abort, resource leak, early exit, etc.
///
/// Please use TempFile unless you absolutely need a named file.
///
pub struct NamedTempFile(Option<NamedTempFileInner>);

struct NamedTempFileInner {
    file: File,
    path: PathBuf,
}

impl fmt::Debug for NamedTempFile {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "NamedTempFile({:?})", self.0.as_ref().unwrap().path)
    }
}

/// Error returned when persisting a temporary file fails
#[derive(Debug)]
pub struct PersistError {
    /// The underlying IO error.
    pub error: io::Error,
    /// The temporary file that couldn't be persisted.
    pub file: NamedTempFile,
}

impl From<PersistError> for io::Error {
    #[inline]
    fn from(error: PersistError) -> io::Error {
        error.error
    }
}

impl fmt::Display for PersistError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "failed to persist temporary file: {}", self.error)
    }
}

impl error::Error for PersistError {
    #[inline]
    fn description(&self) -> &str {
        "failed to persist temporary file"
    }
    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        Some(&self.error)
    }
}

impl NamedTempFile {
    #[inline]
    fn inner(&self) -> &NamedTempFileInner {
        self.0.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut NamedTempFileInner {
        self.0.as_mut().unwrap()
    }

    /// Create a new temporary file.
    ///
    /// *SECURITY WARNING:* This will create a temporary file in the default temporary file
    /// directory (platform dependent). These directories are often patrolled by temporary file
    /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't
    /// delete your file.
    ///
    /// Reasons to use this method:
    ///   1. The file has a short lifetime and your temporary file cleaner is sane (doesn't delete
    ///      recently accessed files).
    ///   2. You trust every user on your system (i.e. you are the only user).
    ///   3. You have disabled your system's temporary file cleaner or verified that your system
    ///      doesn't have a temporary file cleaner.
    ///
    /// Reasons not to use this method:
    ///   1. You'll fix it later. No you won't.
    ///   2. You don't care about the security of the temporary file. If none of the "reasons to
    ///      use this method" apply, referring to a temporary file by name may allow an attacker
    ///      to create/overwrite your non-temporary files. There are exceptions but if you don't
    ///      already know them, don't use this method.
    #[inline]
    pub fn new() -> io::Result<NamedTempFile> {
        Self::new_in(&env::temp_dir())
    }

    /// Create a new temporary file in the specified directory.
    #[inline]
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
        loop {
            let path = dir.as_ref().join(&util::tmpname());
            return match imp::create_named(&path) {
                Ok(file) => Ok(NamedTempFile(Some(NamedTempFileInner { path: path, file: file, }))),
                Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
                Err(e) => Err(e),
            }
        }
    }

    /// Queries metadata about the underlying file.
    #[inline]
    pub fn metadata(&self) -> io::Result<fs::Metadata> {
        self.inner().file.metadata()
    }

    /// Truncate the file to `size` bytes.
    #[inline]
    pub fn set_len(&self, size: u64) -> io::Result<()> {
        self.inner().file.set_len(size)
    }

    /// Get the temporary file's path.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, the path returned by this method may refer to an
    /// attacker controlled file.
    #[inline]
    pub fn path(&self) -> &Path {
        &self.inner().path
    }

    /// Close and remove the temporary file.
    ///
    /// Use this if you want to detect errors in deleting the file.
    #[inline]
    pub fn close(mut self) -> io::Result<()> {
        let NamedTempFileInner { path, file } = self.0.take().unwrap();
        drop(file);
        fs::remove_file(path)
    }

    /// Persist the temporary file at the target path.
    ///
    /// If a file exists at the target path, persist will atomically replace it. If this method
    /// fails, it will return `self` in the resulting PersistError.
    ///
    /// Note: Temporary files cannot be persisted across filesystems.
    ///
    /// *SECURITY WARNING:* Only use this method if you're positive that a temporary file cleaner
    /// won't have deleted your file. Otherwise, you might end up persisting an attacker controlled
    /// file.
    #[inline]
    pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<File, PersistError> {
        match fs::rename(&self.inner().path, new_path) {
            Ok(_) => Ok(self.0.take().unwrap().file),
            Err(e) => Err(PersistError { file: self, error: e }),
        }
    }
}

impl Drop for NamedTempFile {
    #[inline]
    fn drop(&mut self) {
        if let Some(NamedTempFileInner { file, path }) = self.0.take() {
            drop(file);
            let _ = fs::remove_file(path);
        }
    }
}

impl Read for NamedTempFile {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner_mut().file.read(buf)
    }
}

impl Write for NamedTempFile {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner_mut().file.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.inner_mut().file.flush()
    }
}

impl Seek for NamedTempFile {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        self.inner_mut().file.seek(pos)
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for NamedTempFile {
    #[inline]
    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
        self.inner().file.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawHandle for NamedTempFile {
    #[inline]
    fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
        self.inner().file.as_raw_handle()
    }
}
<|endoftext|>


<commit_before>use handlebars_iron::{Template, HandlebarsEngine};

use serde_json::builder::ObjectBuilder;

use serde_json::value::Value;

use iron::prelude::*;
use iron::status;
use router::Router;

use helpers::value_to_json;
use content;

pub fn make_simple_content(title: String, content: String) -> Value {
	return ObjectBuilder::new()
		.insert("title".to_string(), title)
		.insert("content".to_string(), content);
	return object.unwrap();
}

pub fn pages() -> Chain {
	// Make the layout
	let mut router = Router::new();

	router.get("/", |_: &mut Request| {
		let mut resp = Response::new();
		resp.set_mut(Template::new("simple_content", value_to_json(content::make_index()))).set_mut(status::Ok);
    	return Ok(resp);
	});

	let mut chain = Chain::new(router);
	chain.link_after(HandlebarsEngine::new("templates/", ".hbs"));
	return chain;
}
<commit_msg>Fix returning twice with something non-existant.<commit_after>use handlebars_iron::{Template, HandlebarsEngine};

use serde_json::builder::ObjectBuilder;

use serde_json::value::Value;

use iron::prelude::*;
use iron::status;
use router::Router;

use helpers::value_to_json;
use content;

pub fn make_simple_content(title: String, content: String) -> Value {
	return ObjectBuilder::new()
		.insert("title".to_string(), title)
		.insert("content".to_string(), content)
		.unwrap();
}

pub fn pages() -> Chain {
	// Make the layout
	let mut router = Router::new();

	router.get("/", |_: &mut Request| {
		let mut resp = Response::new();
		resp.set_mut(Template::new("simple_content", value_to_json(content::make_index()))).set_mut(status::Ok);
    	return Ok(resp);
	});

	let mut chain = Chain::new(router);
	chain.link_after(HandlebarsEngine::new("templates/", ".hbs"));
	return chain;
}
<|endoftext|>


<commit_before>use errors::*;
use objective::*;
use fnv::FnvHashSet;
use rand::{Rng, thread_rng, sample};
use rand::distributions::{IndependentSample, Range};
use slog::{Drain, Logger};
use slog_stdlog;
use rayon::prelude::*;
use std::f64;
use std::iter::empty;

#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub enum SampleElement<Element> {
    Independent(Element),
    Dependent(Element),
}

/// Compute the total primal curvature between two sets `S` and `T`. The input `ST` should be `S ∪ T`.
///
/// # Errors
/// If $f_{el}(S) = 0$ but $f_{el}(S \cup T) \neq 0$ then `Err(DivideByZero)` is returned.
#[allow(non_snake_case)]
pub fn gamma<O: Objective>(obj: &O,
                           el: O::Element,
                           ST: &FnvHashSet<O::Element>,
                           S: &FnvHashSet<O::Element>,
                           state: &O::State,
                           joint_state: &O::State)
                           -> Result<f64> {
    let lower = obj.delta(el, S, state)?;
    let upper = obj.delta(el, ST, joint_state)?;

    if lower == upper {
        Ok(1.0)
    } else if lower == 0.0 {
        Err(ErrorKind::DivideByZero(upper, lower).into())
    } else {
        Ok(upper / lower)
    }
}

/// Compute `Λ(T, S)`. The ordering of elements `σ` is given by the ordering of `T`.
///
/// # Errors
/// If `T` contains duplicate elements, `Err(DuplicateElements)` is returned.
/// If any `Γ` returns `Err(DivideByZero)`, that is propagated.
#[allow(non_snake_case)]
pub fn lambda<O: Objective>(obj: &O,
                            T: &Vec<SampleElement<O::Element>>,
                            S: &FnvHashSet<O::Element>,
                            state: &O::State)
                            -> Result<f64> {
    let mut Ti = S.clone();
    let mut tstate = state.clone();
    let mut sum = 0.0;
    for t in T {
        if let &SampleElement::Dependent(t) = t {
            if S.contains(&t) {
                continue;
            }
            obj.insert_mut(t, &mut tstate)?;
            sum += gamma(obj, t, &Ti, S, state, &tstate)?;
            Ti.insert(t);
        } else {
            sum += 1.0; // gamma is 1 for independent elements by definition
        }
    }
    Ok(sum)
}

/// Construct a sample `T ~ D_{p,k}` where `p = bias` and `k` is given.
///
/// For worst case, bias should be 1.
#[allow(non_snake_case)]
pub fn biased_dependency_sample<O: Objective>(obj: &O,
                                              bias: f64,
                                              k: usize)
                                              -> Result<Vec<SampleElement<O::Element>>> {
    use ratio::SampleElement::*;
    let mut rng = thread_rng();
    let mut T = Vec::with_capacity(k);
    let uniform = Range::new(0.0, 1.0);

    fn choose<'a, T: 'a + Copy, I: IntoIterator<Item = &'a T>, R: Rng>(rng: &mut R,
                                                                       iter: I)
                                                                       -> Option<T> {
        let res = sample(rng, iter, 1);

        if res.len() == 1 { Some(*res[0]) } else { None }
    }

    use std::hash::Hash;
    fn rejection<'a, T: 'a + Copy + Eq + Hash, R: Rng>(rng: &mut R,
                                                       domain: &Vec<T>,
                                                       reject: &FnvHashSet<T>)
                                                       -> Option<T> {
        loop {
            if let Some(choice) = choose(rng, domain) {
                if !reject.contains(&choice) {
                    return Some(choice);
                }
            } else {
                return None;
            }
        }
    }

    let elements = obj.elements().collect::<Vec<_>>();
    T.push(Dependent(sample(&mut rng, obj.elements(), 1)[0]));

    let deps = |t, supermodular| if let Dependent(t) = t {
        if supermodular {
            obj.supermodular_depends(t, &O::State::default())
        } else {
            obj.depends(t, &O::State::default())
        }
    } else {
        Ok(Box::new(empty::<O::Element>()) as ElementIterator<O>)
    };

    let element_count = obj.elements().count();
    let mut depends = deps(T[0], false)?.collect::<FnvHashSet<_>>();
    let mut superdepends = deps(T[0], true)?.collect::<FnvHashSet<_>>();

    for i in 1..k {
        let x = if uniform.ind_sample(&mut rng) <= bias {
            // dependent
            match choose(&mut rng, &superdepends) {
                None => {
                    if superdepends.len() + T.len() == element_count {
                        // no more independent elements either
                        return Err(ErrorKind::InsufficientElements(k, i - 1).into());
                    } else {
                        Independent(rejection(&mut rng, &elements, &depends).unwrap())
                    }
                }
                Some(x) => Dependent(x),
            }
        } else {
            // independent
            if depends.len() + T.len() == element_count {
                // no more independent elements
                Dependent(choose(&mut rng, &superdepends).ok_or(Error::from(ErrorKind::InsufficientElements(k, i - 1)))?)
            } else {
                Independent(rejection(&mut rng, &elements, &depends).unwrap())
            }
        };

        depends.extend(deps(x, false)?);
        superdepends.extend(deps(x, true)?);

        if let Dependent(_) = x {
            assert!(!T.contains(&x));
        }
        T.push(x);

        for &t in &T {
            let t = match t {
                Dependent(t) => t,
                Independent(t) => t,
            };
            superdepends.remove(&t);
            depends.insert(t);
        }
    }

    assert!(T.len() == k);
    Ok(T)
}

/// Find the value `x` such that `Pr[X ≤ x] ≥ δ` for random variable `X` with `n` i.i.d samples.
///
/// Uses a binary search on the `X_i` to locate a suitable value. The `gap` parameter controls how
/// precise the value found must be: once `max - min <= gap` the binary search will terminate.
///
/// TODO: this could be *much* more efficient than recomputing the cdf for every x tested.
fn empirical_cdf(samples: &Vec<f64>, delta: f64, gap: f64, log: Option<Logger>) -> Result<f64> {
    let log = log.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!()));
    const ITERS_MAX: usize = 100;
    if delta > 1.0 - gap as f64 {
        warn!(log, "δ set to a higher precision than η, binary search may never converge"; "δ" => delta, "η" => gap);
    }
    let n = samples.len();
    let mut max =
        samples.iter().filter(|&f| !f.is_nan()).fold(f64::NEG_INFINITY,
                                                     |max, &cur| if cur > max { cur } else { max });
    let mut min = samples.iter()
        .filter(|&f| !f.is_nan())
        .fold(f64::INFINITY, |min, &cur| if cur < min { cur } else { min });
    assert!(max.is_finite());
    assert!(min.is_finite());

    let cdf = |x| samples.iter().filter(|&xi| *xi <= x).count() as f64 / n as f64;
    let mut iters = 0;

    loop {
        let x = (max + min) / 2.0;
        assert!(x.is_finite());
        debug!(log, "testing"; "x" => x, "gap" => max - min, "max" => max, "min" => min);

        let p = cdf(x);

        if p >= delta && max - min <= gap {
            info!(log, "found x with gap satisfied"; "x" => x, "gap" => max - min, "p" => p);
            return Ok(x);
        } else if max - min <= gap {
            // gotten small enough
            let p = cdf(max);
            assert!(p >= delta);
            info!(log, "gap satisfied, but x not found. using max"; "x" => max, "gap" => max - min, "p" => p);
            return Ok(max);
        }

        if p >= delta {
            debug!(log, "p >= δ"; "p" => p);
            // decrease max
            max = x;
        } else {
            debug!(log, "p < δ"; "p" => p);
            // increase min
            min = x;
        }
        iters += 1;
        if iters > ITERS_MAX {
            crit!(log, "binary search failed to converge (likely due to loss of precision from an abnormal number of ζ events)"; "min" => min, "max" => max, "gap" => max - min, "η" => gap);
            return Err(ErrorKind::NoConvergence(min, max, iters).into());
        }
    }
}

pub fn sample_lambda<O: Objective + Sync>(obj: &O,
                                          sol: &FnvHashSet<O::Element>,
                                          state: O::State,
                                          bias: f64,
                                          k: usize,
                                          num_samples: usize)
                                          -> Result<Vec<f64>>
    where O::Element: Send + Sync,
          O::State: Sync
{
    let mut sample_vec = Vec::with_capacity(num_samples);

    (0..num_samples)
        .into_par_iter()
        .map(|_| {
            let sample = biased_dependency_sample(obj, bias, k)?;
            lambda(obj, &sample, sol, &state)
        })
        .collect_into(&mut sample_vec);

    sample_vec.into_iter().collect::<Result<Vec<_>>>()
}

pub fn estimate_lambda<O: Objective + Sync>(obj: &O,
                                            sol: &FnvHashSet<O::Element>,
                                            state: O::State,
                                            bias: f64,
                                            k: usize,
                                            eps: f64,
                                            delta: f64,
                                            delta2: f64,
                                            eta: f64,
                                            log: Option<Logger>)
                                            -> Result<f64>
    where O::Element: Send + Sync,
          O::State: Sync
{
    let log = log.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!()));

    let num_samples = (1.0 - delta2).ln() / (-2.0 * eps.powi(2));
    // assert!(eps >= (1.0 / (2.0 * num_samples) * 2f64.ln()).sqrt()); // sufficiency condition for the bound.
    assert!((-2.0 * eps.powi(2) * num_samples).exp() <= 0.5);

    let num_samples = num_samples.ceil() as usize;
    info!(log, "constructing samples"; "num_samples" => num_samples);

    let samples = sample_lambda(obj, sol, state, bias, k, num_samples)?;
    assert!(samples.len() == num_samples);
    let num_nans: usize = samples.iter().filter(|&f| f.is_nan() || f.is_infinite()).count();

    if num_nans > 0 {
        crit!(log, "samples contain NaN / infinite values"; "count" => num_nans);
        panic!("samples contain NaN / infinite values");
    }

    let mean = samples.iter().sum::<f64>() / samples.len() as f64;
    let variance = samples.iter().map(|xi| (xi - mean).powi(2)).sum::<f64>() / samples.len() as f64;
    let min = samples.iter().fold(f64::INFINITY, |min, xi| xi.min(min));
    let max = samples.iter().fold(0.0, |max, xi| xi.max(max));

    info!(log, "done sampling"; "mean" => mean, "variance" => variance, "min" => min, "max" => max);

    info!(log, "estimating cdf"; "η" => eta);
    empirical_cdf(&samples, delta, eta, Some(log.new(o!("section" => "cdf"))))
}
<commit_msg>Improved performance of sampling from new dist.<commit_after>use errors::*;
use objective::*;
use fnv::FnvHashSet;
use rand::{Rng, thread_rng, sample};
use rand::distributions::{IndependentSample, Range};
use slog::{Drain, Logger};
use slog_stdlog;
use rayon::prelude::*;
use std::f64;
use std::iter::empty;

#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub enum SampleElement<Element> {
    Independent(Element),
    Dependent(Element),
}

/// Compute the total primal curvature between two sets `S` and `T`. The input `ST` should be `S ∪ T`.
///
/// # Errors
/// If $f_{el}(S) = 0$ but $f_{el}(S \cup T) \neq 0$ then `Err(DivideByZero)` is returned.
#[allow(non_snake_case)]
pub fn gamma<O: Objective>(obj: &O,
                           el: O::Element,
                           ST: &FnvHashSet<O::Element>,
                           S: &FnvHashSet<O::Element>,
                           state: &O::State,
                           joint_state: &O::State)
                           -> Result<f64> {
    let lower = obj.delta(el, S, state)?;
    let upper = obj.delta(el, ST, joint_state)?;

    if lower == upper {
        Ok(1.0)
    } else if lower == 0.0 {
        Err(ErrorKind::DivideByZero(upper, lower).into())
    } else {
        Ok(upper / lower)
    }
}

/// Compute `Λ(T, S)`. The ordering of elements `σ` is given by the ordering of `T`.
///
/// # Errors
/// If `T` contains duplicate elements, `Err(DuplicateElements)` is returned.
/// If any `Γ` returns `Err(DivideByZero)`, that is propagated.
#[allow(non_snake_case)]
pub fn lambda<O: Objective>(obj: &O,
                            T: &Vec<SampleElement<O::Element>>,
                            S: &FnvHashSet<O::Element>,
                            state: &O::State)
                            -> Result<f64> {
    let mut Ti = S.clone();
    let mut tstate = state.clone();
    let mut sum = 0.0;
    for t in T {
        if let &SampleElement::Dependent(t) = t {
            if S.contains(&t) {
                continue;
            }
            obj.insert_mut(t, &mut tstate)?;
            sum += gamma(obj, t, &Ti, S, state, &tstate)?;
            Ti.insert(t);
        } else {
            sum += 1.0; // gamma is 1 for independent elements by definition
        }
    }
    Ok(sum)
}

/// Construct a sample `T ~ D_{p,k}` where `p = bias` and `k` is given.
///
/// For worst case, bias should be 1.
#[allow(non_snake_case)]
pub fn biased_dependency_sample<O: Objective>(obj: &O,
                                              bias: f64,
                                              k: usize)
                                              -> Result<Vec<SampleElement<O::Element>>> {
    use ratio::SampleElement::*;
    let mut rng = thread_rng();
    let mut T = Vec::with_capacity(k);
    let uniform = Range::new(0.0, 1.0);

    fn choose<'a, T: 'a + Copy, I: IntoIterator<Item = &'a T>, R: Rng>(rng: &mut R,
                                                                       iter: I)
                                                                       -> Option<T> {
        let mut iter = iter.into_iter();
        if iter.size_hint().1.unwrap() == 0 {
            return None;
        }
        let range = Range::new(0, iter.size_hint().1.unwrap());
        iter.nth(range.ind_sample(rng)).cloned()
    }

    T.push(Dependent(sample(&mut rng, obj.elements(), 1)[0]));

    let deps = |t, supermodular| if let Dependent(t) = t {
        if supermodular {
            obj.supermodular_depends(t, &O::State::default())
        } else {
            obj.depends(t, &O::State::default())
        }
    } else {
        Ok(Box::new(empty::<O::Element>()) as ElementIterator<O>)
    };

    let element_count = obj.elements().count();
    let mut independent = obj.elements().collect::<FnvHashSet<_>>();
    for dep in deps(T[0], false)? {
        independent.remove(&dep);
    }
    let mut superdepends = deps(T[0], true)?.collect::<FnvHashSet<_>>();

    for i in 1..k {
        let x = if uniform.ind_sample(&mut rng) <= bias {
            // dependent
            match choose(&mut rng, &superdepends) {
                None => {
                    if superdepends.len() + T.len() == element_count {
                        // no more independent elements either
                        return Err(ErrorKind::InsufficientElements(k, i - 1).into());
                    } else {
                        Independent(choose(&mut rng, &independent).unwrap())
                    }
                }
                Some(x) => Dependent(x),
            }
        } else {
            // independent
            if independent.len() == 0 {
                // no more independent elements
                Dependent(choose(&mut rng, &superdepends).ok_or(Error::from(ErrorKind::InsufficientElements(k, i - 1)))?)
            } else {
                Independent(choose(&mut rng, &independent).unwrap())
            }
        };

        for dep in deps(x, false)? {
            independent.remove(&dep);
        }
        superdepends.extend(deps(x, true)?);

        if let Dependent(_) = x {
            assert!(!T.contains(&x));
        }
        T.push(x);

        for &t in &T {
            let t = match t {
                Dependent(t) => t,
                Independent(t) => t,
            };
            superdepends.remove(&t);
            independent.remove(&t);
        }
    }

    assert!(T.len() == k);
    Ok(T)
}

/// Find the value `x` such that `Pr[X ≤ x] ≥ δ` for random variable `X` with `n` i.i.d samples.
///
/// Uses a binary search on the `X_i` to locate a suitable value. The `gap` parameter controls how
/// precise the value found must be: once `max - min <= gap` the binary search will terminate.
///
/// TODO: this could be *much* more efficient than recomputing the cdf for every x tested.
fn empirical_cdf(samples: &Vec<f64>, delta: f64, gap: f64, log: Option<Logger>) -> Result<f64> {
    let log = log.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!()));
    const ITERS_MAX: usize = 100;
    if delta > 1.0 - gap as f64 {
        warn!(log, "δ set to a higher precision than η, binary search may never converge"; "δ" => delta, "η" => gap);
    }
    let n = samples.len();
    let mut max =
        samples.iter().filter(|&f| !f.is_nan()).fold(f64::NEG_INFINITY,
                                                     |max, &cur| if cur > max { cur } else { max });
    let mut min = samples.iter()
        .filter(|&f| !f.is_nan())
        .fold(f64::INFINITY, |min, &cur| if cur < min { cur } else { min });
    assert!(max.is_finite());
    assert!(min.is_finite());

    let cdf = |x| samples.iter().filter(|&xi| *xi <= x).count() as f64 / n as f64;
    let mut iters = 0;

    loop {
        let x = (max + min) / 2.0;
        assert!(x.is_finite());
        debug!(log, "testing"; "x" => x, "gap" => max - min, "max" => max, "min" => min);

        let p = cdf(x);

        if p >= delta && max - min <= gap {
            info!(log, "found x with gap satisfied"; "x" => x, "gap" => max - min, "p" => p);
            return Ok(x);
        } else if max - min <= gap {
            // gotten small enough
            let p = cdf(max);
            assert!(p >= delta);
            info!(log, "gap satisfied, but x not found. using max"; "x" => max, "gap" => max - min, "p" => p);
            return Ok(max);
        }

        if p >= delta {
            debug!(log, "p >= δ"; "p" => p);
            // decrease max
            max = x;
        } else {
            debug!(log, "p < δ"; "p" => p);
            // increase min
            min = x;
        }
        iters += 1;
        if iters > ITERS_MAX {
            crit!(log, "binary search failed to converge (likely due to loss of precision from an abnormal number of ζ events)"; "min" => min, "max" => max, "gap" => max - min, "η" => gap);
            return Err(ErrorKind::NoConvergence(min, max, iters).into());
        }
    }
}

pub fn sample_lambda<O: Objective + Sync>(obj: &O,
                                          sol: &FnvHashSet<O::Element>,
                                          state: O::State,
                                          bias: f64,
                                          k: usize,
                                          num_samples: usize)
                                          -> Result<Vec<f64>>
    where O::Element: Send + Sync,
          O::State: Sync
{
    let mut sample_vec = Vec::with_capacity(num_samples);

    (0..num_samples)
        .into_par_iter()
        .map(|_| {
            let sample = biased_dependency_sample(obj, bias, k)?;
            lambda(obj, &sample, sol, &state)
        })
        .collect_into(&mut sample_vec);

    sample_vec.into_iter().collect::<Result<Vec<_>>>()
}

pub fn estimate_lambda<O: Objective + Sync>(obj: &O,
                                            sol: &FnvHashSet<O::Element>,
                                            state: O::State,
                                            bias: f64,
                                            k: usize,
                                            eps: f64,
                                            delta: f64,
                                            delta2: f64,
                                            eta: f64,
                                            log: Option<Logger>)
                                            -> Result<f64>
    where O::Element: Send + Sync,
          O::State: Sync
{
    let log = log.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!()));

    let num_samples = (1.0 - delta2).ln() / (-2.0 * eps.powi(2));
    // assert!(eps >= (1.0 / (2.0 * num_samples) * 2f64.ln()).sqrt()); // sufficiency condition for the bound.
    assert!((-2.0 * eps.powi(2) * num_samples).exp() <= 0.5);

    let num_samples = num_samples.ceil() as usize;
    info!(log, "constructing samples"; "num_samples" => num_samples);

    let samples = sample_lambda(obj, sol, state, bias, k, num_samples)?;
    assert!(samples.len() == num_samples);
    let num_nans: usize = samples.iter().filter(|&f| f.is_nan() || f.is_infinite()).count();

    if num_nans > 0 {
        crit!(log, "samples contain NaN / infinite values"; "count" => num_nans);
        panic!("samples contain NaN / infinite values");
    }

    let mean = samples.iter().sum::<f64>() / samples.len() as f64;
    let variance = samples.iter().map(|xi| (xi - mean).powi(2)).sum::<f64>() / samples.len() as f64;
    let min = samples.iter().fold(f64::INFINITY, |min, xi| xi.min(min));
    let max = samples.iter().fold(0.0, |max, xi| xi.max(max));

    info!(log, "done sampling"; "mean" => mean, "variance" => variance, "min" => min, "max" => max);

    info!(log, "estimating cdf"; "η" => eta);
    empirical_cdf(&samples, delta, eta, Some(log.new(o!("section" => "cdf"))))
}
<|endoftext|>