<commit_before>extern crate x11_dl;
use self::x11_dl::{xlib, xtest};
use std::ptr;

use super::MouseControllable;

pub struct Enigo {
    pub display: *mut xlib::Display,
    pub window: xlib::Window,
    pub xlib: xlib::Xlib,
    pub xtest: xtest::Xf86vmode,
}

impl MouseControllable for Enigo {
    fn new() -> Self {
        unsafe {
            let xlib = xlib::Xlib::open().unwrap();
            let xtest = xtest::Xf86vmode::open().unwrap();

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display == ptr::null_mut() {
                panic!("can't open display");
            }

            let window = (xlib.XDefaultRootWindow)(display);

            Enigo{ display: display, window: window, xlib: xlib, xtest: xtest }
        }
    }

    fn mouse_move_to(&self, x: i32, y: i32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, self.window, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_move_relative(&self, x: i32, y: i32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, 0, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    //TODO(dustin): make button a new type
    fn mouse_down(&self, button: u32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 1, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_up(&self, button: u32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 0, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_click(&self, button: u32) {
        use std::{thread, time};

        self.mouse_down(button);
        thread::sleep(time::Duration::from_millis(100));
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&self, length: i32) {
        let mut button;
        let mut length = length;

        if length < 0 {
            button = 6;  //scroll left button
        } else {
            button = 7;  //scroll right button
        }

        if(length < 0){
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }

    fn mouse_scroll_y(&self, length: i32) {
        let mut button;
        let mut length = length;

        if length < 0 {
            button = 4;  //scroll up button
        } else {
            button = 5; //scroll down button
        }

        if(length < 0){
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }
}<commit_msg>warnings<commit_after>extern crate x11_dl;
use self::x11_dl::{xlib, xtest};
use std::ptr;

use super::MouseControllable;

pub struct Enigo {
    pub display: *mut xlib::Display,
    pub window: xlib::Window,
    pub xlib: xlib::Xlib,
    pub xtest: xtest::Xf86vmode,
}

impl MouseControllable for Enigo {
    fn new() -> Self {
        unsafe {
            let xlib = xlib::Xlib::open().unwrap();
            let xtest = xtest::Xf86vmode::open().unwrap();

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display == ptr::null_mut() {
                panic!("can't open display");
            }

            let window = (xlib.XDefaultRootWindow)(display);

            Enigo{ display: display, window: window, xlib: xlib, xtest: xtest }
        }
    }

    fn mouse_move_to(&self, x: i32, y: i32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, self.window, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_move_relative(&self, x: i32, y: i32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, 0, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    //TODO(dustin): make button a new type
    fn mouse_down(&self, button: u32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 1, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_up(&self, button: u32) {
        if self.display == ptr::null_mut(){
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 0, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_click(&self, button: u32) {
        use std::{thread, time};

        self.mouse_down(button);
        thread::sleep(time::Duration::from_millis(100));
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 6;  //scroll left button
        } else {
            button = 7;  //scroll right button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }

    fn mouse_scroll_y(&self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 4;  //scroll up button
        } else {
            button = 5; //scroll down button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }
}<|endoftext|>


<commit_before>//! Densely numbered entity references as mapping keys.
//!
//! This module defines an `EntityRef` trait that should be implemented by reference types wrapping
//! a small integer index. The `EntityMap` data structure uses the dense index space to implement a
//! map with a vector. There are primary and secondary entity maps:
//!
//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
//!   allocate new entity references with the `push` method. The values stores in a primary map
//!   must implement the `PrimaryEntityData` marker trait.
//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
//!   values need to implement `Clone + Default` traits so the map can be grown with `ensure`.

use std::vec::Vec;
use std::default::Default;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;

    /// Convert an `EntityRef` to an `Optional<EntityRef>` by using the default value as the null
    /// reference.
    ///
    /// Entity references are often used in compact data structures like linked lists where a
    /// sentinel 'null' value is needed. Normally we would use an `Optional` for that, but
    /// currently that uses twice the memory of a plain `EntityRef`.
    ///
    /// This method is called `wrap()` because it is the inverse of `unwrap()`.
    fn wrap(self) -> Option<Self>
        where Self: Default
    {
        if self == Self::default() {
            None
        } else {
            Some(self)
        }
    }
}

/// A mapping `K -> V` for densely indexed entity references.
#[derive(Debug, Clone)]
pub struct EntityMap<K, V>
    where K: EntityRef
{
    elems: Vec<V>,
    unused: PhantomData<K>,
}

/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
    where K: EntityRef
{
    /// Create a new empty map.
    pub fn new() -> Self {
        EntityMap {
            elems: Vec::new(),
            unused: PhantomData,
        }
    }

    /// Check if `k` is a valid key in the map.
    pub fn is_valid(&self, k: K) -> bool {
        k.index() < self.elems.len()
    }

    /// Iterate over all the keys in this map.
    pub fn keys(&self) -> Keys<K> {
        Keys {
            pos: 0,
            len: self.elems.len(),
            unused: PhantomData,
        }
    }
}

/// A marker trait for data stored in primary entity maps.
///
/// A primary entity map can be used to allocate new entity references with the `push` method. It
/// is important that entity references can't be created anywhere else, so the data stored in a
/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method.
pub trait PrimaryEntityData {}

/// Additional methods for primary entry maps only.
///
/// These are identified by the `PrimaryEntityData` marker trait.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: PrimaryEntityData
{
    /// Get the key that will be assigned to the next pushed value.
    pub fn next_key(&self) -> K {
        K::new(self.elems.len())
    }

    /// Append `v` to the mapping, assigning a new key which is returned.
    pub fn push(&mut self, v: V) -> K {
        let k = self.next_key();
        self.elems.push(v);
        k
    }

    /// Get the total number of entity references created.
    pub fn len(&self) -> usize {
        self.elems.len()
    }
}

/// Additional methods for value types that implement `Clone` and `Default`.
///
/// When the value type implements these additional traits, the `EntityMap` can be resized
/// explicitly with the `ensure` method.
///
/// Use this for secondary maps that are mapping keys created by another primary map.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: Clone + Default
{
    /// Create a new secondary `EntityMap` that is prepared to hold `n` elements.
    ///
    /// Use this when the length of the primary map is known:
    /// ```
    /// let secondary_map = EntityMap::with_capacity(primary_map.len());
    /// ```
    pub fn with_capacity(n: usize) -> Self {
        let mut map = EntityMap {
            elems: Vec::with_capacity(n),
            unused: PhantomData,
        };
        map.elems.resize(n, V::default());
        map
    }

    /// Ensure that `k` is a valid key but adding default entries if necesssary.
    ///
    /// Return a mutable reference to the corresponding entry.
    pub fn ensure(&mut self, k: K) -> &mut V {
        if !self.is_valid(k) {
            self.elems.resize(k.index() + 1, V::default())
        }
        &mut self.elems[k.index()]
    }
}

/// Immutable indexing into an `EntityMap`.
/// The indexed value must be in the map, either because it was created by `push`, or the key was
/// passed to `ensure`.
impl<K, V> Index<K> for EntityMap<K, V>
    where K: EntityRef
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.elems[k.index()]
    }
}

/// Mutable indexing into an `EntityMap`.
/// Use `ensure` instead if the key is not known to be valid.
impl<K, V> IndexMut<K> for EntityMap<K, V>
    where K: EntityRef
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.elems[k.index()]
    }
}

/// Iterate over all keys in order.
pub struct Keys<K>
    where K: EntityRef
{
    pos: usize,
    len: usize,
    unused: PhantomData<K>,
}

impl<K> Iterator for Keys<K>
    where K: EntityRef
{
    type Item = K;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.len {
            let k = K::new(self.pos);
            self.pos += 1;
            Some(k)
        } else {
            None
        }
    }
}

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

    // EntityRef impl for testing.
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct E(u32);

    impl EntityRef for E {
        fn new(i: usize) -> Self {
            E(i as u32)
        }
        fn index(self) -> usize {
            self.0 as usize
        }
    }

    impl PrimaryEntityData for isize {}

    #[test]
    fn basic() {
        let r0 = E(0);
        let r1 = E(1);
        let r2 = E(2);
        let mut m = EntityMap::new();

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, []);

        assert!(!m.is_valid(r0));
        m.ensure(r2);
        m[r2] = 3;
        assert!(m.is_valid(r1));
        m[r1] = 5;

        assert_eq!(m[r1], 5);
        assert_eq!(m[r2], 3);

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, [r0, r1, r2]);

        let shared = &m;
        assert_eq!(shared[r0], 0);
        assert_eq!(shared[r1], 5);
        assert_eq!(shared[r2], 3);
    }

    #[test]
    fn push() {
        let mut m = EntityMap::new();
        let k1: E = m.push(12);
        let k2 = m.push(33);

        assert_eq!(m[k1], 12);
        assert_eq!(m[k2], 33);
    }
}
<commit_msg>Add clear, is_empty, and resize methods to EntityMap.<commit_after>//! Densely numbered entity references as mapping keys.
//!
//! This module defines an `EntityRef` trait that should be implemented by reference types wrapping
//! a small integer index. The `EntityMap` data structure uses the dense index space to implement a
//! map with a vector. There are primary and secondary entity maps:
//!
//! - A *primary* `EntityMap` contains the main definition of an entity, and it can be used to
//!   allocate new entity references with the `push` method. The values stores in a primary map
//!   must implement the `PrimaryEntityData` marker trait.
//! - A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
//!   values need to implement `Clone + Default` traits so the map can be grown with `ensure`.

use std::vec::Vec;
use std::default::Default;
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;

    /// Convert an `EntityRef` to an `Optional<EntityRef>` by using the default value as the null
    /// reference.
    ///
    /// Entity references are often used in compact data structures like linked lists where a
    /// sentinel 'null' value is needed. Normally we would use an `Optional` for that, but
    /// currently that uses twice the memory of a plain `EntityRef`.
    ///
    /// This method is called `wrap()` because it is the inverse of `unwrap()`.
    fn wrap(self) -> Option<Self>
        where Self: Default
    {
        if self == Self::default() {
            None
        } else {
            Some(self)
        }
    }
}

/// A mapping `K -> V` for densely indexed entity references.
#[derive(Debug, Clone)]
pub struct EntityMap<K, V>
    where K: EntityRef
{
    elems: Vec<V>,
    unused: PhantomData<K>,
}

/// Shared `EntityMap` implementation for all value types.
impl<K, V> EntityMap<K, V>
    where K: EntityRef
{
    /// Create a new empty map.
    pub fn new() -> Self {
        EntityMap {
            elems: Vec::new(),
            unused: PhantomData,
        }
    }

    /// Check if `k` is a valid key in the map.
    pub fn is_valid(&self, k: K) -> bool {
        k.index() < self.elems.len()
    }

    /// Is this map completely empty?
    pub fn is_empty(&self) -> bool {
        self.elems.is_empty()
    }

    /// Remove all entries from this map.
    pub fn clear(&mut self) {
        self.elems.clear()
    }

    /// Iterate over all the keys in this map.
    pub fn keys(&self) -> Keys<K> {
        Keys {
            pos: 0,
            len: self.elems.len(),
            unused: PhantomData,
        }
    }
}

/// A marker trait for data stored in primary entity maps.
///
/// A primary entity map can be used to allocate new entity references with the `push` method. It
/// is important that entity references can't be created anywhere else, so the data stored in a
/// primary entity map must be tagged as `PrimaryEntityData` to unlock the `push` method.
pub trait PrimaryEntityData {}

/// Additional methods for primary entry maps only.
///
/// These are identified by the `PrimaryEntityData` marker trait.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: PrimaryEntityData
{
    /// Get the key that will be assigned to the next pushed value.
    pub fn next_key(&self) -> K {
        K::new(self.elems.len())
    }

    /// Append `v` to the mapping, assigning a new key which is returned.
    pub fn push(&mut self, v: V) -> K {
        let k = self.next_key();
        self.elems.push(v);
        k
    }

    /// Get the total number of entity references created.
    pub fn len(&self) -> usize {
        self.elems.len()
    }
}

/// Additional methods for value types that implement `Clone` and `Default`.
///
/// When the value type implements these additional traits, the `EntityMap` can be resized
/// explicitly with the `ensure` method.
///
/// Use this for secondary maps that are mapping keys created by another primary map.
impl<K, V> EntityMap<K, V>
    where K: EntityRef,
          V: Clone + Default
{
    /// Create a new secondary `EntityMap` that is prepared to hold `n` elements.
    ///
    /// Use this when the length of the primary map is known:
    /// ```
    /// let secondary_map = EntityMap::with_capacity(primary_map.len());
    /// ```
    pub fn with_capacity(n: usize) -> Self {
        let mut map = EntityMap {
            elems: Vec::with_capacity(n),
            unused: PhantomData,
        };
        map.elems.resize(n, V::default());
        map
    }

    /// Resize the map to have `n` entries by adding default entries as needed.
    pub fn resize(&mut self, n: usize) {
        self.elems.resize(n, V::default());
    }

    /// Ensure that `k` is a valid key but adding default entries if necesssary.
    ///
    /// Return a mutable reference to the corresponding entry.
    pub fn ensure(&mut self, k: K) -> &mut V {
        if !self.is_valid(k) {
            self.resize(k.index() + 1)
        }
        &mut self.elems[k.index()]
    }
}

/// Immutable indexing into an `EntityMap`.
/// The indexed value must be in the map, either because it was created by `push`, or the key was
/// passed to `ensure`.
impl<K, V> Index<K> for EntityMap<K, V>
    where K: EntityRef
{
    type Output = V;

    fn index(&self, k: K) -> &V {
        &self.elems[k.index()]
    }
}

/// Mutable indexing into an `EntityMap`.
/// Use `ensure` instead if the key is not known to be valid.
impl<K, V> IndexMut<K> for EntityMap<K, V>
    where K: EntityRef
{
    fn index_mut(&mut self, k: K) -> &mut V {
        &mut self.elems[k.index()]
    }
}

/// Iterate over all keys in order.
pub struct Keys<K>
    where K: EntityRef
{
    pos: usize,
    len: usize,
    unused: PhantomData<K>,
}

impl<K> Iterator for Keys<K>
    where K: EntityRef
{
    type Item = K;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.len {
            let k = K::new(self.pos);
            self.pos += 1;
            Some(k)
        } else {
            None
        }
    }
}

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

    // EntityRef impl for testing.
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    struct E(u32);

    impl EntityRef for E {
        fn new(i: usize) -> Self {
            E(i as u32)
        }
        fn index(self) -> usize {
            self.0 as usize
        }
    }

    impl PrimaryEntityData for isize {}

    #[test]
    fn basic() {
        let r0 = E(0);
        let r1 = E(1);
        let r2 = E(2);
        let mut m = EntityMap::new();

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, []);

        assert!(!m.is_valid(r0));
        m.ensure(r2);
        m[r2] = 3;
        assert!(m.is_valid(r1));
        m[r1] = 5;

        assert_eq!(m[r1], 5);
        assert_eq!(m[r2], 3);

        let v: Vec<E> = m.keys().collect();
        assert_eq!(v, [r0, r1, r2]);

        let shared = &m;
        assert_eq!(shared[r0], 0);
        assert_eq!(shared[r1], 5);
        assert_eq!(shared[r2], 3);
    }

    #[test]
    fn push() {
        let mut m = EntityMap::new();
        let k1: E = m.push(12);
        let k2 = m.push(33);

        assert_eq!(m[k1], 12);
        assert_eq!(m[k2], 33);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-lexer-test FIXME #15877

//! Windows specific console TTY implementation
//!
//! This module contains the implementation of a Windows specific console TTY.
//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole
//! will panic when the codepage is set to UTF-8 and a Unicode character is
//! entered.
//!
//! FIXME
//! This implementation does not account for codepoints that are split across
//! multiple reads and writes. Also, this implementation does not expose a way
//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
//! wrapper that performs encoding/decoding, this implementation should switch
//! to working in raw UTF-16, with such a wrapper around it.

use prelude::v1::*;

use old_io::{self, IoError, IoResult, MemReader};
use iter::repeat;
use libc::types::os::arch::extra::LPCVOID;
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
use libc::{get_osfhandle, CloseHandle};
use mem;
use ptr;
use str::from_utf8;
use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
use super::c::{CONSOLE_SCREEN_BUFFER_INFO};
use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
use super::c::{GetConsoleScreenBufferInfo};

fn invalid_encoding() -> IoError {
    IoError {
        kind: old_io::InvalidInput,
        desc: "text was not valid unicode",
        detail: None,
    }
}

pub fn is_tty(fd: c_int) -> bool {
    let mut out: DWORD = 0;
    // If this function doesn't panic then fd is a TTY
    match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
                                  &mut out as LPDWORD) } {
        0 => false,
        _ => true,
    }
}

pub struct TTY {
    closeme: bool,
    handle: HANDLE,
    utf8: MemReader,
}

impl TTY {
    pub fn new(fd: c_int) -> IoResult<TTY> {
        if is_tty(fd) {
            // If the file descriptor is one of stdin, stderr, or stdout
            // then it should not be closed by us
            let closeme = match fd {
                0...2 => false,
                _ => true,
            };
            let handle = unsafe { get_osfhandle(fd) as HANDLE };
            Ok(TTY {
                handle: handle,
                utf8: MemReader::new(Vec::new()),
                closeme: closeme,
            })
        } else {
            Err(IoError {
                kind: old_io::MismatchedFileTypeForOperation,
                desc: "invalid handle provided to function",
                detail: None,
            })
        }
    }

    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        // Read more if the buffer is empty
        if self.utf8.eof() {
            let mut utf16: Vec<u16> = repeat(0u16).take(0x1000).collect();
            let mut num: DWORD = 0;
            match unsafe { ReadConsoleW(self.handle,
                                         utf16.as_mut_ptr() as LPVOID,
                                         utf16.len() as u32,
                                         &mut num as LPDWORD,
                                         ptr::null_mut()) } {
                0 => return Err(super::last_error()),
                _ => (),
            };
            utf16.truncate(num as uint);
            let utf8 = match String::from_utf16(&utf16) {
                Ok(utf8) => utf8.into_bytes(),
                Err(..) => return Err(invalid_encoding()),
            };
            self.utf8 = MemReader::new(utf8);
        }
        // MemReader shouldn't error here since we just filled it
        Ok(self.utf8.read(buf).unwrap())
    }

    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let utf16 = match from_utf8(buf).ok() {
            Some(utf8) => {
                utf8.utf16_units().collect::<Vec<u16>>()
            }
            None => return Err(invalid_encoding()),
        };
        let mut num: DWORD = 0;
        match unsafe { WriteConsoleW(self.handle,
                                     utf16.as_ptr() as LPCVOID,
                                     utf16.len() as u32,
                                     &mut num as LPDWORD,
                                     ptr::null_mut()) } {
            0 => Err(super::last_error()),
            _ => Ok(()),
        }
    }

    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        // FIXME
        // Somebody needs to decide on which of these flags we want
        match unsafe { SetConsoleMode(self.handle,
            match raw {
                true => 0,
                false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
                         ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
                         ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
            }) } {
            0 => Err(super::last_error()),
            _ => Ok(()),
        }
    }

    pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
        let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
        match unsafe { GetConsoleScreenBufferInfo(self.handle, &mut info as *mut _) } {
            0 => Err(super::last_error()),
            _ => Ok(((info.srWindow.Right + 1 - info.srWindow.Left) as int,
                     (info.srWindow.Bottom + 1 - info.srWindow.Top) as int)),
        }
    }
}

impl Drop for TTY {
    fn drop(&mut self) {
        if self.closeme {
            // Nobody cares about the return value
            let _ = unsafe { CloseHandle(self.handle) };
        }
    }
}
<commit_msg>Revert a wrong replace of "fail" to "panic"<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-lexer-test FIXME #15877

//! Windows specific console TTY implementation
//!
//! This module contains the implementation of a Windows specific console TTY.
//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole
//! will panic when the codepage is set to UTF-8 and a Unicode character is
//! entered.
//!
//! FIXME
//! This implementation does not account for codepoints that are split across
//! multiple reads and writes. Also, this implementation does not expose a way
//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
//! wrapper that performs encoding/decoding, this implementation should switch
//! to working in raw UTF-16, with such a wrapper around it.

use prelude::v1::*;

use old_io::{self, IoError, IoResult, MemReader};
use iter::repeat;
use libc::types::os::arch::extra::LPCVOID;
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
use libc::{get_osfhandle, CloseHandle};
use mem;
use ptr;
use str::from_utf8;
use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
use super::c::{CONSOLE_SCREEN_BUFFER_INFO};
use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
use super::c::{GetConsoleScreenBufferInfo};

fn invalid_encoding() -> IoError {
    IoError {
        kind: old_io::InvalidInput,
        desc: "text was not valid unicode",
        detail: None,
    }
}

pub fn is_tty(fd: c_int) -> bool {
    let mut out: DWORD = 0;
    // If this function doesn't return an error, then fd is a TTY
    match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
                                  &mut out as LPDWORD) } {
        0 => false,
        _ => true,
    }
}

pub struct TTY {
    closeme: bool,
    handle: HANDLE,
    utf8: MemReader,
}

impl TTY {
    pub fn new(fd: c_int) -> IoResult<TTY> {
        if is_tty(fd) {
            // If the file descriptor is one of stdin, stderr, or stdout
            // then it should not be closed by us
            let closeme = match fd {
                0...2 => false,
                _ => true,
            };
            let handle = unsafe { get_osfhandle(fd) as HANDLE };
            Ok(TTY {
                handle: handle,
                utf8: MemReader::new(Vec::new()),
                closeme: closeme,
            })
        } else {
            Err(IoError {
                kind: old_io::MismatchedFileTypeForOperation,
                desc: "invalid handle provided to function",
                detail: None,
            })
        }
    }

    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        // Read more if the buffer is empty
        if self.utf8.eof() {
            let mut utf16: Vec<u16> = repeat(0u16).take(0x1000).collect();
            let mut num: DWORD = 0;
            match unsafe { ReadConsoleW(self.handle,
                                         utf16.as_mut_ptr() as LPVOID,
                                         utf16.len() as u32,
                                         &mut num as LPDWORD,
                                         ptr::null_mut()) } {
                0 => return Err(super::last_error()),
                _ => (),
            };
            utf16.truncate(num as uint);
            let utf8 = match String::from_utf16(&utf16) {
                Ok(utf8) => utf8.into_bytes(),
                Err(..) => return Err(invalid_encoding()),
            };
            self.utf8 = MemReader::new(utf8);
        }
        // MemReader shouldn't error here since we just filled it
        Ok(self.utf8.read(buf).unwrap())
    }

    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let utf16 = match from_utf8(buf).ok() {
            Some(utf8) => {
                utf8.utf16_units().collect::<Vec<u16>>()
            }
            None => return Err(invalid_encoding()),
        };
        let mut num: DWORD = 0;
        match unsafe { WriteConsoleW(self.handle,
                                     utf16.as_ptr() as LPCVOID,
                                     utf16.len() as u32,
                                     &mut num as LPDWORD,
                                     ptr::null_mut()) } {
            0 => Err(super::last_error()),
            _ => Ok(()),
        }
    }

    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        // FIXME
        // Somebody needs to decide on which of these flags we want
        match unsafe { SetConsoleMode(self.handle,
            match raw {
                true => 0,
                false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
                         ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
                         ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
            }) } {
            0 => Err(super::last_error()),
            _ => Ok(()),
        }
    }

    pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
        let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
        match unsafe { GetConsoleScreenBufferInfo(self.handle, &mut info as *mut _) } {
            0 => Err(super::last_error()),
            _ => Ok(((info.srWindow.Right + 1 - info.srWindow.Left) as int,
                     (info.srWindow.Bottom + 1 - info.srWindow.Top) as int)),
        }
    }
}

impl Drop for TTY {
    fn drop(&mut self) {
        if self.closeme {
            // Nobody cares about the return value
            let _ = unsafe { CloseHandle(self.handle) };
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, ISO_8859_2, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {
    /// Obtain the defined term (unique name) of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 101** (ISO-8859-1): Right-hand part of the latin alphabet no. 1,
    /// the Western Europe character set.
    IsoIr100,
    /// **ISO-IR 101** (ISO-8859-2): Right-hand part of the latin alphabet no. 2,
    /// the Eastern Europe character set.
    IsoIr101,
    /// **ISO-IR 192**:: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

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

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" | "ISO_IR 6" => Some(Default),
            "ISO_IR_100" | "ISO_IR 100" => Some(IsoIr100),
            "ISO_IR_101" | "ISO_IR 101" => Some(IsoIr101),
            "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr100 => Some(Box::new(IsoIr100CharacterSetCodec)),
            SpecificCharacterSet::IsoIr101 => Some(Box::new(IsoIr101CharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Data type representing the default character set.
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the ISO-IR 100 characters set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct IsoIr100CharacterSetCodec;

impl TextCodec for IsoIr100CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 100"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the ISO-IR 101 characters set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct IsoIr101CharacterSetCodec;

impl TextCodec for IsoIr101CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 101"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        ISO_8859_2
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_2
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the UTF-8 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Copy)]
pub struct Utf8CharacterSetCodec;

impl TextCodec for Utf8CharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 192"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        UTF_8
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        UTF_8
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// Data type representing the GB18030 character set.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy)]
pub struct Gb18030CharacterSetCodec;

impl TextCodec for Gb18030CharacterSetCodec {
    fn name(&self) -> &'static str {
        "GB18030"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        GB18030
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        GB18030
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

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

    #[test]
    fn iso_ir_6_baseline() {
        let codec = SpecificCharacterSet::Default
            .codec()
            .expect("Must be fully supported");
        assert_eq!(codec.decode(b"Smith^John").unwrap(), "Smith^John");
    }

    #[test]
    fn iso_ir_192_baseline() {
        let codec = SpecificCharacterSet::IsoIr192
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec.decode("Simões^John".as_bytes()).unwrap(),
            "Simões^John",
        );
        assert_eq!(
            codec.decode("Иванков^Андрей".as_bytes()).unwrap(),
            "Иванков^Андрей",
        );
    }

    #[test]
    fn iso_ir_100_baseline() {
        let codec = SpecificCharacterSet::IsoIr100
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"Sim\xF5es^Jo\xE3o").unwrap(), "Simões^João");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_101_baseline() {
        let codec = SpecificCharacterSet::IsoIr101
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }
}
<commit_msg>[encoding] more character sets<commit_after>//! This module contains reusable components for encoding and decoding text in DICOM
//! data structures, including support for character repertoires.
//!
//! The Character Repertoires supported by DICOM are:
//! - ISO 8859
//! - JIS X 0201-1976 Code for Information Interchange
//! - JIS X 0208-1990 Code for the Japanese Graphic Character set for information interchange
//! - JIS X 0212-1990 Code of the supplementary Japanese Graphic Character set for information interchange
//! - KS X 1001 (registered as ISO-IR 149) for Korean Language
//! - TIS 620-2533 (1990) Thai Characters Code for Information Interchange
//! - ISO 10646-1, 10646-2, and their associated supplements and extensions for Unicode character set
//! - GB 18030
//! - GB2312
//!
//! At the moment, text encoding support is limited.
//! Please see [`SpecificCharacterSet`] for a complete enumeration
//! of all supported character encoding in the crate.
//!
//! [`SpecificCharacterSet`]: ./enum.SpecificCharacterSet.html

use crate::error::{Result, TextEncodingError};
use encoding::all::{GB18030, ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, UTF_8};
use encoding::{DecoderTrap, EncoderTrap, Encoding, RawDecoder, StringWriter};
use std::fmt::Debug;

/// A holder of encoding and decoding mechanisms for text in DICOM content,
/// which according to the standard, depends on the specific character set.
pub trait TextCodec {
    /// Obtain the defined term (unique name) of the text encoding,
    /// which may be used as the value of a
    /// Specific Character Set (0008, 0005) element to refer to this codec.
    ///
    /// Should contain no leading or trailing spaces.
    /// This method may be useful for testing purposes, considering that
    /// `TextCodec` is often used as a trait object.
    fn name(&self) -> &'static str;

    /// Decode the given byte buffer as a single string. The resulting string
    /// _may_ contain backslash characters ('\') to delimit individual values,
    /// and should be split later on if required.
    fn decode(&self, text: &[u8]) -> Result<String>;

    /// Encode a text value into a byte vector. The input string can
    /// feature multiple text values by using the backslash character ('\')
    /// as the value delimiter.
    fn encode(&self, text: &str) -> Result<Vec<u8>>;
}

impl<T: ?Sized> TextCodec for Box<T>
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        self.as_ref().name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        self.as_ref().decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        self.as_ref().encode(text)
    }
}

impl<'a, T: ?Sized> TextCodec for &'a T
where
    T: TextCodec,
{
    fn name(&self) -> &'static str {
        (**self).name()
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        (**self).decode(text)
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        (**self).encode(text)
    }
}

/// Type alias for a type erased text codec.
///
/// It is important because stateful decoders may need to change the expected
/// text encoding format at run-time.
pub type DynamicTextCodec = Box<dyn TextCodec>;

/// An enum type for all currently supported character sets.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum SpecificCharacterSet {
    /// **ISO-IR 6**: the default character set.
    Default,
    /// **ISO-IR 101** (ISO-8859-1): Right-hand part of the Latin alphabet no. 1,
    /// the Western Europe character set.
    IsoIr100,
    /// **ISO-IR 101** (ISO-8859-2): Right-hand part of the Latin alphabet no. 2,
    /// the Central/Eastern Europe character set.
    IsoIr101,
    /// **ISO-IR 109** (ISO-8859-3): Right-hand part of the Latin alphabet no. 3,
    /// the South Europe character set.
    IsoIr109,
    /// **ISO-IR 110** (ISO-8859-4): Right-hand part of the Latin alphabet no. 4,
    /// the North Europe character set.
    IsoIr110,
    /// **ISO-IR 144** (ISO-8859-5): The Latin/Cyrillic character set.
    IsoIr144,
    /// **ISO-IR 192**: The Unicode character set based on the UTF-8 encoding.
    IsoIr192,
    /// **GB18030**: The Simplified Chinese character set.
    GB18030,
    // Support for more text encodings is tracked in issue #40.
}

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

impl SpecificCharacterSet {
    pub fn from_code(uid: &str) -> Option<Self> {
        use self::SpecificCharacterSet::*;
        match uid.trim_end() {
            "Default" | "ISO_IR_6" | "ISO_IR 6" | "ISO 2022 IR 6" => Some(Default),
            "ISO_IR_100" | "ISO_IR 100" | "ISO 2022 IR 100" => Some(IsoIr100),
            "ISO_IR_101" | "ISO_IR 101" | "ISO 2022 IR 101" => Some(IsoIr101),
            "ISO_IR_109" | "ISO_IR 109" | "ISO 2022 IR 109" => Some(IsoIr109),
            "ISO_IR_110" | "ISO_IR 110" | "ISO 2022 IR 110" => Some(IsoIr110),
            "ISO_IR_144" | "ISO_IR 144" | "ISO 2022 IR 144" => Some(IsoIr144),
            "ISO_IR_192" | "ISO_IR 192" => Some(IsoIr192),
            "GB18030" => Some(GB18030),
            _ => None,
        }
    }

    /// Retrieve the respective text codec.
    pub fn codec(self) -> Option<DynamicTextCodec> {
        match self {
            SpecificCharacterSet::Default => Some(Box::new(DefaultCharacterSetCodec)),
            SpecificCharacterSet::IsoIr100 => Some(Box::new(IsoIr100CharacterSetCodec)),
            SpecificCharacterSet::IsoIr101 => Some(Box::new(IsoIr101CharacterSetCodec)),
            SpecificCharacterSet::IsoIr109 => Some(Box::new(IsoIr109CharacterSetCodec)),
            SpecificCharacterSet::IsoIr110 => Some(Box::new(IsoIr110CharacterSetCodec)),
            SpecificCharacterSet::IsoIr144 => Some(Box::new(IsoIr144CharacterSetCodec)),
            SpecificCharacterSet::IsoIr192 => Some(Box::new(Utf8CharacterSetCodec)),
            SpecificCharacterSet::GB18030 => Some(Box::new(Gb18030CharacterSetCodec)),
        }
    }
}

fn decode_text_trap(
    _decoder: &mut dyn RawDecoder,
    input: &[u8],
    output: &mut dyn StringWriter,
) -> bool {
    let c = input[0];
    let o0 = c & 7;
    let o1 = (c & 56) >> 3;
    let o2 = (c & 192) >> 6;
    output.write_char('\\');
    output.write_char((o2 + b'0') as char);
    output.write_char((o1 + b'0') as char);
    output.write_char((o0 + b'0') as char);
    true
}

/// Create and implement a character set type using the `encoding` crate.
macro_rules! decl_character_set {
    ($typ: ident, $term: literal, $val: expr) => {
        #[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
        #[doc = "Data type for the "]
        #[doc = $term]
        #[doc = "character set encoding."]
        pub struct $typ;

        impl TextCodec for $typ {
            fn name(&self) -> &'static str {
                $term
            }

            fn decode(&self, text: &[u8]) -> Result<String> {
                $val
                    .decode(text, DecoderTrap::Call(decode_text_trap))
                    .map_err(|e| TextEncodingError::new(e).into())
            }

            fn encode(&self, text: &str) -> Result<Vec<u8>> {
                $val
                    .encode(text, EncoderTrap::Strict)
                    .map_err(|e| TextEncodingError::new(e).into())
            }
        }
    };
}

/// Data type representing the default character set.
#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
pub struct DefaultCharacterSetCodec;

impl TextCodec for DefaultCharacterSetCodec {
    fn name(&self) -> &'static str {
        "ISO_IR 6"
    }

    fn decode(&self, text: &[u8]) -> Result<String> {
        // Using 8859-1 because it is a superset. Reiterations of this impl
        // should check for invalid character codes (#40).
        ISO_8859_1
            .decode(text, DecoderTrap::Call(decode_text_trap))
            .map_err(|e| TextEncodingError::new(e).into())
    }

    fn encode(&self, text: &str) -> Result<Vec<u8>> {
        ISO_8859_1
            .encode(text, EncoderTrap::Strict)
            .map_err(|e| TextEncodingError::new(e).into())
    }
}

decl_character_set!(IsoIr100CharacterSetCodec, "ISO_IR 100", ISO_8859_1);
decl_character_set!(IsoIr101CharacterSetCodec, "ISO_IR 101", ISO_8859_2);
decl_character_set!(IsoIr109CharacterSetCodec, "ISO_IR 109", ISO_8859_3);
decl_character_set!(IsoIr110CharacterSetCodec, "ISO_IR 110", ISO_8859_4);
decl_character_set!(IsoIr144CharacterSetCodec, "ISO_IR 144", ISO_8859_5);
decl_character_set!(Utf8CharacterSetCodec, "ISO_IR 192", UTF_8);
decl_character_set!(Gb18030CharacterSetCodec, "GB18030", GB18030);

/// The result of a text validation procedure (please see [`validate_iso_8859`]).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum TextValidationOutcome {
    /// The text is fully valid and can be safely decoded.
    Ok,
    /// Some characters may have to be replaced, other than that the text can be safely decoded.
    BadCharacters,
    /// The text cannot be decoded.
    NotOk,
}

/// Check whether the given byte slice contains valid text from the default character repertoire.
pub fn validate_iso_8859(text: &[u8]) -> TextValidationOutcome {
    if ISO_8859_1.decode(text, DecoderTrap::Strict).is_err() {
        match ISO_8859_1.decode(text, DecoderTrap::Call(decode_text_trap)) {
            Ok(_) => TextValidationOutcome::BadCharacters,
            Err(_) => TextValidationOutcome::NotOk,
        }
    } else {
        TextValidationOutcome::Ok
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date value representation.
pub fn validate_da(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| c >= b'0' && c <= b'9') {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Time value representation.
pub fn validate_tm(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'\\' | b'.' | b'-' | b' ' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Date Time value representation.
pub fn validate_dt(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b'.' | b'-' | b'+' | b' ' | b'\\' => true,
        c => c >= b'0' && c <= b'9',
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

/// Check whether the given byte slice contains only valid characters for a
/// Code String value representation.
pub fn validate_cs(text: &[u8]) -> TextValidationOutcome {
    if text.iter().cloned().all(|c| match c {
        b' ' | b'_' => true,
        c => (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'Z'),
    }) {
        TextValidationOutcome::Ok
    } else {
        TextValidationOutcome::NotOk
    }
}

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

    #[test]
    fn iso_ir_6_baseline() {
        let codec = SpecificCharacterSet::Default
            .codec()
            .expect("Must be fully supported");
        assert_eq!(codec.decode(b"Smith^John").unwrap(), "Smith^John");
    }

    #[test]
    fn iso_ir_192_baseline() {
        let codec = SpecificCharacterSet::IsoIr192
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec.decode("Simões^John".as_bytes()).unwrap(),
            "Simões^John",
        );
        assert_eq!(
            codec.decode("Иванков^Андрей".as_bytes()).unwrap(),
            "Иванков^Андрей",
        );
    }

    #[test]
    fn iso_ir_100_baseline() {
        let codec = SpecificCharacterSet::IsoIr100
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"Sim\xF5es^Jo\xE3o").unwrap(), "Simões^João");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_101_baseline() {
        let codec = SpecificCharacterSet::IsoIr101
            .codec()
            .expect("Should be fully supported");
        assert_eq!(codec.decode(b"G\xfcnther^Hans").unwrap(), "Günther^Hans");
    }

    #[test]
    fn iso_ir_144_baseline() {
        let codec = SpecificCharacterSet::IsoIr144
            .codec()
            .expect("Should be fully supported");
        assert_eq!(
            codec
                .decode(b"\xb8\xd2\xd0\xdd\xda\xde\xd2^\xb0\xdd\xd4\xe0\xd5\xd9")
                .unwrap(),
            "Иванков^Андрей",
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>added non compression for yt handler, creating new tasks per playlist entry fixed spaces Fixes #12<commit_after><|endoftext|>


<commit_before>use autocfg;

fn main() {
    autocfg::new().emit_sysroot_crate("alloc");
}
<commit_msg>Add forbid unsafe code to build (#98)<commit_after>#![forbid(unsafe_code)]
use autocfg;

fn main() {
    autocfg::new().emit_sysroot_crate("alloc");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate log4rs;

extern crate pencil;
use pencil::{Pencil, Request, Response, PencilResult, PenHTTPError};
use pencil::http_errors::BadRequest;

#[macro_use]
extern crate hyper;

use std::io::Read;

extern crate url;
use url::form_urlencoded;

extern crate webdriver;
use webdriver::response::{WebDriverResponse, ValueResponse};
use std::time;
use std::thread;

extern crate rustc_serialize;

extern crate image;
use std::io::Cursor;

extern crate get_if_addrs;

mod chromedriver;

fn streams(request: &mut Request) -> PencilResult {
    let mut buffer = String::new();
    request.request.read_to_string(&mut buffer).unwrap();
    let mut parse = form_urlencoded::parse(buffer.as_bytes());
    let url = match parse.find(|k| k.0 == "url") {
        Some((_, value)) => value.into_owned(),
        None => {
            warn!("No URL in request");
            return Err(PenHTTPError(BadRequest));
        }
    };
    let request_url = match url::Url::parse(&url) {
        Ok(value) => value,
        Err(_) => {
            warn!("Request URL was dodgy: '{}'", url);
            return Err(PenHTTPError(BadRequest));
        }
    };
    let host = request_url.host_str().unwrap();
    let xpath = match host {
            "livestream.com" => "//div[@id='image-container']/img",
            "www.ustream.tv" => "//video[@id='UViewer']",
            "www.youtube.com" => "//div[@id='player']",
            _ => {
                warn!("Request URL host ({}) wasn't in known list: '{}'",
                      host,
                      url);
                return Err(PenHTTPError(BadRequest));
            }
        }
        .to_string();

    let client = chromedriver::Webdriver::new();
    let session = client.make_session();
    session.goto_url(url);
    thread::sleep(time::Duration::from_secs(5));
    let element: ValueResponse = match session.find_element_by_xpath(xpath) {
        Err(val) => {
            warn!("Error while trying to get element: {:?}", val);
            return Err(PenHTTPError(BadRequest));
        }
        Ok(val) => {
            match val {
                WebDriverResponse::Generic(obj) => obj,
                _ => {
                    warn!("Didn't expect {:?}", val);
                    return Err(PenHTTPError(BadRequest));
                }
            }
        }
    };
    let element_location =
        session.get_element_location(&element).unwrap().find("value").expect("value").clone();
    let element_size =
        session.get_element_size(&element).unwrap().find("value").expect("value").clone();
    let screenshot = session.get_screenshot_as_png().unwrap();

    let cursor = Cursor::new(&screenshot);
    let mut loaded_image = image::load(cursor, image::ImageFormat::PNG).unwrap();
    let cropped = loaded_image.crop(
		element_location.find("x").expect("x").as_u64().expect("numeric x") as u32,
		element_location.find("y").expect("y").as_u64().expect("numeric y") as u32,
		element_size.find("width").expect("width").as_u64().expect("numeric width") as u32,
		element_size.find("height").expect("height").as_u64().expect("numeric height") as u32);

    let mut output_buffer: Vec<u8> = Vec::new();
    cropped.save(&mut output_buffer, image::ImageFormat::PNG).unwrap();
    let mut response = Response::from(output_buffer);
    response.set_content_type("image/png");
    Ok(response)
}

fn make_app() -> Pencil {
    let mut app = Pencil::new("");
    app.set_debug(true);
    app.set_log_level();
    app.post("/streams", "streams", streams);
    return app;
}

fn main() {
    log4rs::init_file("log.toml", Default::default()).unwrap();
    let port = 8000;
    let mut handles = Vec::new();
    for iface in get_if_addrs::get_if_addrs().unwrap() {
        handles.push(::std::thread::spawn(move || {
            let ip = iface.ip();
            let app = make_app();
            info!("Listening on {}:{} for {}", ip, port, iface.name);
            app.run((ip, port));
        }));
    }

    info!("All listeners spawned");

    for handle in handles {
        handle.join().unwrap();
    }
}
<commit_msg>Make Youtube videos play so we get something usable in the imager<commit_after>#[macro_use]
extern crate log;
extern crate log4rs;

extern crate pencil;
use pencil::{Pencil, Request, Response, PencilResult, PenHTTPError};
use pencil::http_errors::BadRequest;

#[macro_use]
extern crate hyper;

use std::io::Read;

extern crate url;
use url::form_urlencoded;

extern crate webdriver;
use webdriver::response::{WebDriverResponse, ValueResponse};
use std::time;
use std::thread;

extern crate rustc_serialize;

extern crate image;
use std::io::Cursor;

extern crate get_if_addrs;

mod chromedriver;

fn streams(request: &mut Request) -> PencilResult {
    let mut buffer = String::new();
    request.request.read_to_string(&mut buffer).unwrap();
    let mut parse = form_urlencoded::parse(buffer.as_bytes());
    let mut url = match parse.find(|k| k.0 == "url") {
        Some((_, value)) => value.into_owned(),
        None => {
            warn!("No URL in request");
            return Err(PenHTTPError(BadRequest));
        }
    };
    let request_url = match url::Url::parse(&url) {
        Ok(value) => value,
        Err(_) => {
            warn!("Request URL was dodgy: '{}'", url);
            return Err(PenHTTPError(BadRequest));
        }
    };
    let host = request_url.host_str().unwrap();
    let xpath = match host {
            "livestream.com" => "//div[@id='image-container']/img",
            "www.ustream.tv" => "//video[@id='UViewer']",
            "www.youtube.com" => {
                url = url + "?autoplay=1";
                "//div[@id='player']"
            }
            _ => {
                warn!("Request URL host ({}) wasn't in known list: '{}'",
                      host,
                      url);
                return Err(PenHTTPError(BadRequest));
            }
        }
        .to_string();

    let client = chromedriver::Webdriver::new();
    let session = client.make_session();
    session.goto_url(url);
    thread::sleep(time::Duration::from_secs(5));
    let element: ValueResponse = match session.find_element_by_xpath(xpath) {
        Err(val) => {
            warn!("Error while trying to get element: {:?}", val);
            return Err(PenHTTPError(BadRequest));
        }
        Ok(val) => {
            match val {
                WebDriverResponse::Generic(obj) => obj,
                _ => {
                    warn!("Didn't expect {:?}", val);
                    return Err(PenHTTPError(BadRequest));
                }
            }
        }
    };
    let element_location =
        session.get_element_location(&element).unwrap().find("value").expect("value").clone();
    let element_size =
        session.get_element_size(&element).unwrap().find("value").expect("value").clone();
    let screenshot = session.get_screenshot_as_png().unwrap();

    let cursor = Cursor::new(&screenshot);
    let mut loaded_image = image::load(cursor, image::ImageFormat::PNG).unwrap();
    let cropped = loaded_image.crop(
		element_location.find("x").expect("x").as_u64().expect("numeric x") as u32,
		element_location.find("y").expect("y").as_u64().expect("numeric y") as u32,
		element_size.find("width").expect("width").as_u64().expect("numeric width") as u32,
		element_size.find("height").expect("height").as_u64().expect("numeric height") as u32);

    let mut output_buffer: Vec<u8> = Vec::new();
    cropped.save(&mut output_buffer, image::ImageFormat::PNG).unwrap();
    let mut response = Response::from(output_buffer);
    response.set_content_type("image/png");
    Ok(response)
}

fn make_app() -> Pencil {
    let mut app = Pencil::new("");
    app.set_debug(true);
    app.set_log_level();
    app.post("/streams", "streams", streams);
    return app;
}

fn main() {
    log4rs::init_file("log.toml", Default::default()).unwrap();
    let port = 8000;
    let mut handles = Vec::new();
    for iface in get_if_addrs::get_if_addrs().unwrap() {
        handles.push(::std::thread::spawn(move || {
            let ip = iface.ip();
            let app = make_app();
            info!("Listening on {}:{} for {}", ip, port, iface.name);
            app.run((ip, port));
        }));
    }

    info!("All listeners spawned");

    for handle in handles {
        handle.join().unwrap();
    }
}
<|endoftext|>


<commit_before>//! Miscellaneous algorithms.

/// A comparator on partially ordered elements, that panics if they are incomparable
pub fn asserting_cmp<T: PartialOrd>(a: &T, b: &T) -> std::cmp::Ordering {
    a.partial_cmp(b).expect("Comparing incomparable elements")
}

/// Assuming slice is sorted and totally ordered, returns the minimum i for which
/// slice[i] >= key, or slice.len() if no such i exists
pub fn slice_lower_bound<T: PartialOrd>(slice: &[T], key: &T) -> usize {
    slice
        .binary_search_by(|x| asserting_cmp(x, key).then(std::cmp::Ordering::Greater))
        .unwrap_err()
}

/// Assuming slice is sorted and totally ordered, returns the minimum i for which
/// slice[i] > key, or slice.len() if no such i exists
pub fn slice_upper_bound<T: PartialOrd>(slice: &[T], key: &T) -> usize {
    slice
        .binary_search_by(|x| asserting_cmp(x, key).then(std::cmp::Ordering::Less))
        .unwrap_err()
}

/// Merge two sorted and totally ordered collections into one
pub fn merge_sorted<T: PartialOrd>(
    i1: impl IntoIterator<Item = T>,
    i2: impl IntoIterator<Item = T>,
) -> Vec<T> {
    let (mut i1, mut i2) = (i1.into_iter().peekable(), i2.into_iter().peekable());
    let mut merged = Vec::with_capacity(i1.size_hint().0 + i2.size_hint().0);
    while let (Some(a), Some(b)) = (i1.peek(), i2.peek()) {
        merged.push(if a <= b { i1.next() } else { i2.next() }.unwrap());
    }
    merged.extend(i1.chain(i2));
    merged
}

/// A stable sort
pub fn merge_sort<T: Ord>(mut v: Vec<T>) -> Vec<T> {
    if v.len() < 2 {
        v
    } else {
        let v2 = v.split_off(v.len() / 2);
        merge_sorted(merge_sort(v), merge_sort(v2))
    }
}

/// A simple data structure for coordinate compression
pub struct SparseIndex {
    coords: Vec<i64>,
}

impl SparseIndex {
    /// Build an index, given the full set of coordinates to compress.
    pub fn new(mut coords: Vec<i64>) -> Self {
        coords.sort_unstable();
        coords.dedup();
        Self { coords }
    }

    /// Return Ok(i) if the coordinate q appears at index i
    /// Return Err(i) if q appears between indices i-1 and i
    pub fn compress(&self, q: i64) -> Result<usize, usize> {
        self.coords.binary_search(&q)
    }
}

/// Represents a maximum (upper envelope) of a collection of linear functions of one
/// variable, evaluated using an online version of the convex hull trick.
/// It combines the offline algorithm with square root decomposition, resulting in an
/// asymptotically suboptimal but simple algorithm with good amortized performnce:
/// For N inserts interleaved with Q queries, a threshold of N/sqrt(Q) yields
/// O(N sqrt Q + Q log N) time complexity. If all queries come after all inserts,
/// any threshold less than N (e.g., 0) yields O(N + Q log N) time complexity.
pub struct PiecewiseLinearConvexFn {
    recent_lines: Vec<(f64, f64)>,
    sorted_lines: Vec<(f64, f64)>,
    intersections: Vec<f64>,
    merge_threshold: usize,
}

impl PiecewiseLinearConvexFn {
    /// Initializes with a given threshold for re-running the convex hull algorithm
    pub fn with_merge_threshold(merge_threshold: usize) -> Self {
        Self {
            recent_lines: vec![],
            sorted_lines: vec![],
            intersections: vec![],
            merge_threshold,
        }
    }

    /// Replaces the represented function with the maximum of itself and a provided line
    pub fn max_with(&mut self, new_m: f64, new_b: f64) {
        self.recent_lines.push((new_m, new_b));
    }

    /// Similar to max_with but requires that (new_m, new_b) be the largest pair so far
    fn max_with_sorted(&mut self, new_m: f64, new_b: f64) {
        while let Some(&(last_m, last_b)) = self.sorted_lines.last() {
            // If slopes are equal, get rid of the old line as its intercept is lower
            if (new_m - last_m).abs() > 1e-9 {
                let intersect = (new_b - last_b) / (last_m - new_m);
                if self.intersections.last() < Some(&intersect) {
                    self.intersections.push(intersect);
                    break;
                }
            }
            self.intersections.pop();
            self.sorted_lines.pop();
        }
        self.sorted_lines.push((new_m, new_b));
    }

    /// Evaluates the function at x
    fn eval_unoptimized(&self, x: f64) -> f64 {
        let idx = slice_lower_bound(&self.intersections, &x);
        self.recent_lines
            .iter()
            .chain(self.sorted_lines.get(idx))
            .map(|&(m, b)| m * x + b)
            .max_by(asserting_cmp)
            .unwrap_or(-1e18)
    }

    /// Evaluates the function at x with good amortized runtime
    pub fn evaluate(&mut self, x: f64) -> f64 {
        if self.recent_lines.len() > self.merge_threshold {
            self.recent_lines.sort_unstable_by(asserting_cmp);
            self.intersections.clear();
            let all_lines = merge_sorted(self.recent_lines.drain(..), self.sorted_lines.drain(..));
            for (new_m, new_b) in all_lines {
                self.max_with_sorted(new_m, new_b);
            }
        }
        self.eval_unoptimized(x)
    }
}

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

    #[test]
    fn test_bounds() {
        let mut vals = vec![16, 45, 45, 45, 82];

        assert_eq!(slice_upper_bound(&vals, &44), 1);
        assert_eq!(slice_lower_bound(&vals, &45), 1);
        assert_eq!(slice_upper_bound(&vals, &45), 4);
        assert_eq!(slice_lower_bound(&vals, &46), 4);

        vals.dedup();
        for (i, q) in vals.iter().enumerate() {
            assert_eq!(slice_lower_bound(&vals, q), i);
            assert_eq!(slice_upper_bound(&vals, q), i + 1);
        }
    }

    #[test]
    fn test_merge_sorted() {
        let vals1 = vec![16, 45, 45, 82];
        let vals2 = vec![-20, 40, 45, 50];
        let vals_merged = vec![-20, 16, 40, 45, 45, 45, 50, 82];

        assert_eq!(merge_sorted(None, Some(42)), vec![42]);
        assert_eq!(merge_sorted(vals1.iter().cloned(), None), vals1);
        assert_eq!(merge_sorted(vals1, vals2), vals_merged);
    }

    #[test]
    fn test_merge_sort() {
        let unsorted = vec![8, -5, 1, 4, -3, 4];
        let sorted = vec![-5, -3, 1, 4, 4, 8];

        assert_eq!(merge_sort(unsorted), sorted);
        assert_eq!(merge_sort(sorted.clone()), sorted);
    }

    #[test]
    fn test_coord_compress() {
        let mut coords = vec![16, 99, 45, 18];
        let index = SparseIndex::new(coords.clone());

        coords.sort_unstable();
        for (i, q) in coords.into_iter().enumerate() {
            assert_eq!(index.compress(q - 1), Err(i));
            assert_eq!(index.compress(q), Ok(i));
            assert_eq!(index.compress(q + 1), Err(i + 1));
        }
    }

    #[test]
    fn test_range_compress() {
        let queries = vec![(0, 10), (10, 19), (20, 29)];
        let coords = queries.iter().flat_map(|&(i, j)| vec![i, j + 1]).collect();
        let index = SparseIndex::new(coords);

        assert_eq!(index.coords, vec![0, 10, 11, 20, 30]);
    }

    #[test]
    fn test_convex_hull_trick() {
        let lines = [(0, -3), (-1, 0), (1, -8), (-2, 1), (1, -4)];
        let xs = [0, 1, 2, 3, 4, 5];
        // results[i] consists of the expected y-coordinates after processing
        // the first i+1 lines.
        let results = [
            [-3, -3, -3, -3, -3, -3],
            [0, -1, -2, -3, -3, -3],
            [0, -1, -2, -3, -3, -3],
            [1, -1, -2, -3, -3, -3],
            [1, -1, -2, -1, 0, 1],
        ];
        for threshold in 0..=lines.len() {
            let mut func = PiecewiseLinearConvexFn::with_merge_threshold(threshold);
            assert_eq!(func.evaluate(0.0), -1e18);
            for (&(slope, intercept), expected) in lines.iter().zip(results.iter()) {
                func.max_with(slope as f64, intercept as f64);
                let ys: Vec<i64> = xs.iter().map(|&x| func.evaluate(x as f64) as i64).collect();
                assert_eq!(expected, &ys[..]);
            }
        }
    }
}
<commit_msg>Remove merge_threshold parameter and add proof<commit_after>//! Miscellaneous algorithms.

/// A comparator on partially ordered elements, that panics if they are incomparable
pub fn asserting_cmp<T: PartialOrd>(a: &T, b: &T) -> std::cmp::Ordering {
    a.partial_cmp(b).expect("Comparing incomparable elements")
}

/// Assuming slice is sorted and totally ordered, returns the minimum i for which
/// slice[i] >= key, or slice.len() if no such i exists
pub fn slice_lower_bound<T: PartialOrd>(slice: &[T], key: &T) -> usize {
    slice
        .binary_search_by(|x| asserting_cmp(x, key).then(std::cmp::Ordering::Greater))
        .unwrap_err()
}

/// Assuming slice is sorted and totally ordered, returns the minimum i for which
/// slice[i] > key, or slice.len() if no such i exists
pub fn slice_upper_bound<T: PartialOrd>(slice: &[T], key: &T) -> usize {
    slice
        .binary_search_by(|x| asserting_cmp(x, key).then(std::cmp::Ordering::Less))
        .unwrap_err()
}

/// Stably merges two sorted and totally ordered collections into one
pub fn merge_sorted<T: PartialOrd>(
    i1: impl IntoIterator<Item = T>,
    i2: impl IntoIterator<Item = T>,
) -> Vec<T> {
    let mut i1 = i1.into_iter().peekable();
    let mut i2 = i2.into_iter().peekable();
    let mut merged = Vec::with_capacity(i1.size_hint().0 + i2.size_hint().0);
    while let (Some(a), Some(b)) = (i1.peek(), i2.peek()) {
        merged.push(if a <= b { i1.next() } else { i2.next() }.unwrap());
    }
    merged.extend(i1.chain(i2));
    merged
}

/// A stable sort
pub fn merge_sort<T: Ord>(mut v: Vec<T>) -> Vec<T> {
    if v.len() < 2 {
        v
    } else {
        let v2 = v.split_off(v.len() / 2);
        merge_sorted(merge_sort(v), merge_sort(v2))
    }
}

/// A simple data structure for coordinate compression
pub struct SparseIndex {
    coords: Vec<i64>,
}

impl SparseIndex {
    /// Builds an index, given the full set of coordinates to compress.
    pub fn new(mut coords: Vec<i64>) -> Self {
        coords.sort_unstable();
        coords.dedup();
        Self { coords }
    }

    /// Returns Ok(i) if the coordinate q appears at index i
    /// Returns Err(i) if q appears between indices i-1 and i
    pub fn compress(&self, q: i64) -> Result<usize, usize> {
        self.coords.binary_search(&q)
    }
}

/// Represents a maximum (upper envelope) of a collection of linear functions of one
/// variable, evaluated using an online version of the convex hull trick.
/// It combines the offline algorithm with square root decomposition, resulting in an
/// asymptotically suboptimal but simple algorithm with good amortized performance:
/// N inserts interleaved with Q queries yields O(N sqrt Q + Q log N) time complexity
/// in general, or O(N + Q log N) if all queries come after all inserts.
// Proof: the Q log N term comes from calls to slice_lower_bound(). As for the N sqrt Q,
//        note that between successive times when the hull is rebuilt, O(N) work is done,
//        and the running totals of insertions and queries satisfy del_N (del_Q + 1) > N.
//        Now, either del_Q >= sqrt Q, or else del_Q <= 2 sqrt Q - 1
//                                          => del_N > N / (2 sqrt Q).
//        Since del(N sqrt Q) >= max(N del(sqrt Q), del_N sqrt Q)
//                            >= max(N del_Q / (2 sqrt Q), del_N sqrt Q),
//        we conclude that del(N sqrt Q) >= N / 2.
#[derive(Default)]
pub struct PiecewiseLinearConvexFn {
    recent_lines: Vec<(f64, f64)>,
    sorted_lines: Vec<(f64, f64)>,
    intersections: Vec<f64>,
    amortized_work: usize,
}

impl PiecewiseLinearConvexFn {
    /// Replaces the represented function with the maximum of itself and a provided line
    pub fn max_with(&mut self, new_m: f64, new_b: f64) {
        self.recent_lines.push((new_m, new_b));
    }

    /// Similar to max_with but requires that (new_m, new_b) be the largest pair so far
    fn max_with_sorted(&mut self, new_m: f64, new_b: f64) {
        while let Some(&(last_m, last_b)) = self.sorted_lines.last() {
            // If slopes are equal, get rid of the old line as its intercept is lower
            if (new_m - last_m).abs() > 1e-9 {
                let intersect = (new_b - last_b) / (last_m - new_m);
                if self.intersections.last() < Some(&intersect) {
                    self.intersections.push(intersect);
                    break;
                }
            }
            self.intersections.pop();
            self.sorted_lines.pop();
        }
        self.sorted_lines.push((new_m, new_b));
    }

    /// Evaluates the function at x
    fn eval_unoptimized(&self, x: f64) -> f64 {
        let idx = slice_lower_bound(&self.intersections, &x);
        self.recent_lines
            .iter()
            .chain(self.sorted_lines.get(idx))
            .map(|&(m, b)| m * x + b)
            .max_by(asserting_cmp)
            .unwrap_or(-1e18)
    }

    /// Evaluates the function at x with good amortized runtime
    pub fn evaluate(&mut self, x: f64) -> f64 {
        self.amortized_work += self.recent_lines.len();
        if self.amortized_work > self.sorted_lines.len() {
            self.amortized_work = 0;
            self.recent_lines.sort_unstable_by(asserting_cmp);
            self.intersections.clear();
            let all_lines = merge_sorted(self.recent_lines.drain(..), self.sorted_lines.drain(..));
            for (new_m, new_b) in all_lines {
                self.max_with_sorted(new_m, new_b);
            }
        }
        self.eval_unoptimized(x)
    }
}

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

    #[test]
    fn test_bounds() {
        let mut vals = vec![16, 45, 45, 45, 82];

        assert_eq!(slice_upper_bound(&vals, &44), 1);
        assert_eq!(slice_lower_bound(&vals, &45), 1);
        assert_eq!(slice_upper_bound(&vals, &45), 4);
        assert_eq!(slice_lower_bound(&vals, &46), 4);

        vals.dedup();
        for (i, q) in vals.iter().enumerate() {
            assert_eq!(slice_lower_bound(&vals, q), i);
            assert_eq!(slice_upper_bound(&vals, q), i + 1);
        }
    }

    #[test]
    fn test_merge_sorted() {
        let vals1 = vec![16, 45, 45, 82];
        let vals2 = vec![-20, 40, 45, 50];
        let vals_merged = vec![-20, 16, 40, 45, 45, 45, 50, 82];

        assert_eq!(merge_sorted(None, Some(42)), vec![42]);
        assert_eq!(merge_sorted(vals1.iter().cloned(), None), vals1);
        assert_eq!(merge_sorted(vals1, vals2), vals_merged);
    }

    #[test]
    fn test_merge_sort() {
        let unsorted = vec![8, -5, 1, 4, -3, 4];
        let sorted = vec![-5, -3, 1, 4, 4, 8];

        assert_eq!(merge_sort(unsorted), sorted);
        assert_eq!(merge_sort(sorted.clone()), sorted);
    }

    #[test]
    fn test_coord_compress() {
        let mut coords = vec![16, 99, 45, 18];
        let index = SparseIndex::new(coords.clone());

        coords.sort_unstable();
        for (i, q) in coords.into_iter().enumerate() {
            assert_eq!(index.compress(q - 1), Err(i));
            assert_eq!(index.compress(q), Ok(i));
            assert_eq!(index.compress(q + 1), Err(i + 1));
        }
    }

    #[test]
    fn test_range_compress() {
        let queries = vec![(0, 10), (10, 19), (20, 29)];
        let coords = queries.iter().flat_map(|&(i, j)| vec![i, j + 1]).collect();
        let index = SparseIndex::new(coords);

        assert_eq!(index.coords, vec![0, 10, 11, 20, 30]);
    }

    #[test]
    fn test_convex_hull_trick() {
        let lines = [(0, -3), (-1, 0), (1, -8), (-2, 1), (1, -4)];
        let xs = [0, 1, 2, 3, 4, 5];
        // results[i] consists of the expected y-coordinates after processing
        // the first i+1 lines.
        let results = [
            [-3, -3, -3, -3, -3, -3],
            [0, -1, -2, -3, -3, -3],
            [0, -1, -2, -3, -3, -3],
            [1, -1, -2, -3, -3, -3],
            [1, -1, -2, -1, 0, 1],
        ];
        let mut func = PiecewiseLinearConvexFn::default();
        assert_eq!(func.evaluate(0.0), -1e18);
        for (&(slope, intercept), expected) in lines.iter().zip(results.iter()) {
            func.max_with(slope as f64, intercept as f64);
            let ys: Vec<i64> = xs.iter().map(|&x| func.evaluate(x as f64) as i64).collect();
            assert_eq!(expected, &ys[..]);
        }
    }
}
<|endoftext|>