<commit_before>use webcore::value::{Value, Reference, ConversionError};
use webcore::try_from::{TryFrom, TryInto};
use webcore::unsafe_typed_array::UnsafeTypedArray;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::blob::Blob;
use webapi::array_buffer::ArrayBuffer;
use webapi::dom_exception::{InvalidAccessError, SecurityError, SyntaxError};

use std::error;
use std::fmt;

/// Wrapper type around a CloseEvent code, indicating why the WebSocket was closed
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent)
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SocketCloseCode(pub u16);

// Close codes are defined here:
// https://tools.ietf.org/html/rfc6455#section-7.4
newtype_enum!(SocketCloseCode {
    /// Normal closure; the connection successfully completed whatever purpose for which it was
    /// created.
    NORMAL_CLOSURE = 1000,
    /// The endpoint is going away, either because of a server failure or because the browser is
    /// navigating away from the page that opened the connection.
    GOING_AWAY = 1001,
    /// The endpoint is terminating the connection due to a protocol error.
    PROTOCOL_ERROR = 1002,
    /// The connection is being terminated because the endpoint received data of a type it cannot
    /// accept (for example, a text-only endpoint received binary data).
    UNSUPPORTED_DATA = 1003,
    /// Reserved. Indicates that no status code was provided even though one was expected.
    NO_STATUS_RECEIVED = 1005,
    /// Reserved. Used to indicate that a connection was closed abnormally (that is, with no close
    /// frame being sent) when a status code is expected.
    ABNORMAL_CLOSURE = 1006,
    /// The endpoint is terminating the connection because a message was received that contained
    /// inconsistent data (e.g., non-UTF-8 data within a text message).
    INVALID_FRAME_PAYLOAD_DATA = 1007,
    /// The endpoint is terminating the connection because it received a message that violates its
    /// policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
    POLICY_VIOLATION = 1008,
    /// The endpoint is terminating the connection because a data frame was received that is too
    /// large.
    MESSAGE_TOO_BIG = 1009,
    /// The client is terminating the connection because it expected the server to negotiate one or
    /// more extensions, but the server didn't.
    MISSING_EXTENSION = 1010,
    /// The server is terminating the connection because it encountered an unexpected condition
    /// that prevented it from fulfilling the request.
    INTERNAL_ERROR = 1011,
    /// The server is terminating the connection because it is restarting.
    SERVICE_RESTART = 1012,
    /// The server is terminating the connection due to a temporary condition, e.g. it is
    /// overloaded and is casting off some of its clients.
    TRY_AGAIN_LATER = 1013,
    /// The server was acting as a gateway or proxy and received an invalid response from the
    /// upstream server. This is similar to 502 HTTP Status Code.
    BAD_GATEWAY = 1014,
    /// Reserved. Indicates that the connection was closed due to a failure to perform a TLS
    /// handshake (e.g., the server certificate can't be verified).
    TLS_HANDSHAKE = 1015,
});

/// The WebSocket object provides the API for creating and managing a WebSocket connection to a
/// server, as well as for sending and receiving data on the connection.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
pub struct WebSocket( Reference );

// WebSocket specification:
// https://html.spec.whatwg.org/multipage/web-sockets.html#the-websocket-interface

impl IEventTarget for WebSocket {}

reference_boilerplate! {
    WebSocket,
    instanceof WebSocket
    convertible to EventTarget
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BinaryType {
    Blob,
    ArrayBuffer
}

impl BinaryType {
    fn to_str(self) -> &'static str {
        match self {
            BinaryType::Blob => "blob",
            BinaryType::ArrayBuffer => "arraybuffer",
        }
    }
    fn from_str(s: &str) -> Self {
        match s {
            "blob" => BinaryType::Blob,
            "arraybuffer" => BinaryType::ArrayBuffer,
            other => panic!("Invalid binary type: {:?}", other)
        }
    }
}

/// A number indicating the state of the `WebSocket`.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants)
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SocketReadyState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3
}

impl TryFrom<Value> for SocketReadyState {
    type Error = ConversionError;

    /// Performs the conversion.
    fn try_from(v: Value) -> Result<SocketReadyState, ConversionError> {
        match v.try_into()? {
            0 => Ok(SocketReadyState::Connecting),
            1 => Ok(SocketReadyState::Open),
            2 => Ok(SocketReadyState::Closing),
            3 => Ok(SocketReadyState::Closed),
            other => Err(ConversionError::Custom(format!("Unknown ready_state: {}", other)))
        }
    }
}

impl WebSocket {
    /// Returns a newly constructed `WebSocket`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn new(url: &str) -> Result<WebSocket, CreationError> {
        js_try!(
            return new WebSocket(@{url});
        ).unwrap()
    }

    /// Returns a newly constructed `WebSocket`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn new_with_protocols(url: &str, protocols: &[&str]) -> Result<WebSocket, CreationError> {
        js_try!(
            return new WebSocket(@{url}, @{protocols});
        ).unwrap()
    }

    /// Returns the binary type of the web socket. Only affects received messages.
    /// The default binary type is `Blob`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn binary_type(&self) -> BinaryType {
        let binary_type: String = js!( return @{self}.binaryType; ).try_into().unwrap();
        BinaryType::from_str(&binary_type)
    }

    /// Sets the binary type of the web socket. Only affects received messages.
    /// The default binary type is `Blob`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn set_binary_type(&self, binary_type: BinaryType) {
        js!( @(no_return) @{self}.binaryType = @{binary_type.to_str()}; );
    }

    /// Returns the number of bytes of data that have been queued using calls to send()
    /// but not yet transmitted to the network. This value resets to zero once all queued
    /// data has been sent. This value does not reset to zero when the connection is closed;
    /// if you keep calling send(), this will continue to climb.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn buffered_amount(&self) -> u64 {
        js!( return @{self}.bufferedAmount; ).try_into().unwrap()
    }

    /// Returns the extensions selected by the server. This is currently only the empty
    /// string or a list of extensions as negotiated by the connection.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn extensions(&self) -> String {
        js!( return @{self}.extensions; ).try_into().unwrap()
    }

    /// Returns a string indicating the name of the sub-protocol the server selected;
    /// this will be one of the strings specified in the protocols parameter when
    /// creating the WebSocket object.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn protocol(&self) -> String {
        js!( return @{self}.protocol; ).try_into().unwrap()
    }

    /// Returns the current state of the connection.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn ready_state(&self) -> SocketReadyState {
        js!( return @{self}.protocol; ).try_into().unwrap()
    }

    /// Returns the URL as resolved by the constructor. This is always an absolute URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn url(&self) -> String {
        js!( return @{self}.url; ).try_into().unwrap()
    }

    /// Closes the WebSocket connection or connection attempt, if any. If the connection
    /// is already CLOSED, this method does nothing.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#close())
    pub fn close(&self) {
        js!( @(no_return) @{self}.close(); );
    }

    /// Closes the WebSocket connection or connection attempt, if any. If the connection
    /// is already CLOSED, this method does nothing.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#close())
    pub fn close_with_status(&self, code: SocketCloseCode, reason: &str) -> Result<(), CloseError> {
        js_try!( @(no_return)
            @{self}.close(@{code.0}, @{reason});
        ).unwrap()
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_text(&self, text: &str) {
        js!( @(no_return) @{self}.send(@{text}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_blob(&self, blob: &Blob) {
        js!( @(no_return) @{self}.send(@{blob}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_array_buffer(&self, array_buffer: &ArrayBuffer) {
        js!( @(no_return) @{self}.send(@{array_buffer}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_bytes(&self, bytes: &[u8]) {
        js!( @(no_return) @{self}.send(@{ UnsafeTypedArray(bytes) }); );
    }
}

/// Errors thrown by `WebSocket::new`.
error_enum_boilerplate! {
    CreationError,
    SecurityError, SyntaxError
}

/// Errors thrown by `WebSocket::close_with_status`.
error_enum_boilerplate! {
    CloseError,
    InvalidAccessError, SyntaxError
}

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

    #[test]
    fn test_close_codes() {
        assert_eq!(&format!("{:?}", SocketCloseCode::NORMAL_CLOSURE), "SocketCloseCode::NORMAL_CLOSURE");
        assert_eq!(&format!("{:?}", SocketCloseCode::GOING_AWAY), "SocketCloseCode::GOING_AWAY");
        assert_eq!(&format!("{:?}", SocketCloseCode(1000)), "SocketCloseCode::NORMAL_CLOSURE");
        assert_eq!(&format!("{:?}", SocketCloseCode(3001)), "SocketCloseCode(3001)");
    }

    #[test]
    fn test_new() {
        assert!(WebSocket::new("ws://localhost").is_ok());

        match WebSocket::new("bad url") {
            Err(CreationError::SyntaxError(_)) => (),
            v => panic!("expected SyntaxError, got {:?}", v),
        }
    }

    #[test]
    fn test_close() {
        let socket = WebSocket::new("ws://localhost").unwrap();

        socket.close();

        assert!(socket.close_with_status( SocketCloseCode::NORMAL_CLOSURE, "closed" ).is_ok());

        // Invalid close code
        match socket.close_with_status( SocketCloseCode(12345), "closed" ) {
            Err(CloseError::InvalidAccessError(_)) => (),
            v => panic!("expected InvalidAccessError, got {:?}", v),
        }

        // Close reason too long (>123 bytes according to spec)
        match socket.close_with_status(
            SocketCloseCode::NORMAL_CLOSURE,
            &(0..200).map(|_| "X").collect::<String>()
        ) {
            Err(CloseError::SyntaxError(_)) => (),
            v => panic!("expected SyntaxError, got {:?}", v),
        }
    }
}
<commit_msg>Fix WebSocket tests<commit_after>use webcore::value::{Value, Reference, ConversionError};
use webcore::try_from::{TryFrom, TryInto};
use webcore::unsafe_typed_array::UnsafeTypedArray;
use webapi::event_target::{IEventTarget, EventTarget};
use webapi::blob::Blob;
use webapi::array_buffer::ArrayBuffer;
use webapi::dom_exception::{InvalidAccessError, SecurityError, SyntaxError};

use std::error;
use std::fmt;

/// Wrapper type around a CloseEvent code, indicating why the WebSocket was closed
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent)
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SocketCloseCode(pub u16);

// Close codes are defined here:
// https://tools.ietf.org/html/rfc6455#section-7.4
newtype_enum!(SocketCloseCode {
    /// Normal closure; the connection successfully completed whatever purpose for which it was
    /// created.
    NORMAL_CLOSURE = 1000,
    /// The endpoint is going away, either because of a server failure or because the browser is
    /// navigating away from the page that opened the connection.
    GOING_AWAY = 1001,
    /// The endpoint is terminating the connection due to a protocol error.
    PROTOCOL_ERROR = 1002,
    /// The connection is being terminated because the endpoint received data of a type it cannot
    /// accept (for example, a text-only endpoint received binary data).
    UNSUPPORTED_DATA = 1003,
    /// Reserved. Indicates that no status code was provided even though one was expected.
    NO_STATUS_RECEIVED = 1005,
    /// Reserved. Used to indicate that a connection was closed abnormally (that is, with no close
    /// frame being sent) when a status code is expected.
    ABNORMAL_CLOSURE = 1006,
    /// The endpoint is terminating the connection because a message was received that contained
    /// inconsistent data (e.g., non-UTF-8 data within a text message).
    INVALID_FRAME_PAYLOAD_DATA = 1007,
    /// The endpoint is terminating the connection because it received a message that violates its
    /// policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
    POLICY_VIOLATION = 1008,
    /// The endpoint is terminating the connection because a data frame was received that is too
    /// large.
    MESSAGE_TOO_BIG = 1009,
    /// The client is terminating the connection because it expected the server to negotiate one or
    /// more extensions, but the server didn't.
    MISSING_EXTENSION = 1010,
    /// The server is terminating the connection because it encountered an unexpected condition
    /// that prevented it from fulfilling the request.
    INTERNAL_ERROR = 1011,
    /// The server is terminating the connection because it is restarting.
    SERVICE_RESTART = 1012,
    /// The server is terminating the connection due to a temporary condition, e.g. it is
    /// overloaded and is casting off some of its clients.
    TRY_AGAIN_LATER = 1013,
    /// The server was acting as a gateway or proxy and received an invalid response from the
    /// upstream server. This is similar to 502 HTTP Status Code.
    BAD_GATEWAY = 1014,
    /// Reserved. Indicates that the connection was closed due to a failure to perform a TLS
    /// handshake (e.g., the server certificate can't be verified).
    TLS_HANDSHAKE = 1015,
});

/// The WebSocket object provides the API for creating and managing a WebSocket connection to a
/// server, as well as for sending and receiving data on the connection.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
pub struct WebSocket( Reference );

// WebSocket specification:
// https://html.spec.whatwg.org/multipage/web-sockets.html#the-websocket-interface

impl IEventTarget for WebSocket {}

reference_boilerplate! {
    WebSocket,
    instanceof WebSocket
    convertible to EventTarget
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BinaryType {
    Blob,
    ArrayBuffer
}

impl BinaryType {
    fn to_str(self) -> &'static str {
        match self {
            BinaryType::Blob => "blob",
            BinaryType::ArrayBuffer => "arraybuffer",
        }
    }
    fn from_str(s: &str) -> Self {
        match s {
            "blob" => BinaryType::Blob,
            "arraybuffer" => BinaryType::ArrayBuffer,
            other => panic!("Invalid binary type: {:?}", other)
        }
    }
}

/// A number indicating the state of the `WebSocket`.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants)
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SocketReadyState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3
}

impl TryFrom<Value> for SocketReadyState {
    type Error = ConversionError;

    /// Performs the conversion.
    fn try_from(v: Value) -> Result<SocketReadyState, ConversionError> {
        match v.try_into()? {
            0 => Ok(SocketReadyState::Connecting),
            1 => Ok(SocketReadyState::Open),
            2 => Ok(SocketReadyState::Closing),
            3 => Ok(SocketReadyState::Closed),
            other => Err(ConversionError::Custom(format!("Unknown ready_state: {}", other)))
        }
    }
}

impl WebSocket {
    /// Returns a newly constructed `WebSocket`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn new(url: &str) -> Result<WebSocket, CreationError> {
        js_try!(
            return new WebSocket(@{url});
        ).unwrap()
    }

    /// Returns a newly constructed `WebSocket`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn new_with_protocols(url: &str, protocols: &[&str]) -> Result<WebSocket, CreationError> {
        js_try!(
            return new WebSocket(@{url}, @{protocols});
        ).unwrap()
    }

    /// Returns the binary type of the web socket. Only affects received messages.
    /// The default binary type is `Blob`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn binary_type(&self) -> BinaryType {
        let binary_type: String = js!( return @{self}.binaryType; ).try_into().unwrap();
        BinaryType::from_str(&binary_type)
    }

    /// Sets the binary type of the web socket. Only affects received messages.
    /// The default binary type is `Blob`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn set_binary_type(&self, binary_type: BinaryType) {
        js!( @(no_return) @{self}.binaryType = @{binary_type.to_str()}; );
    }

    /// Returns the number of bytes of data that have been queued using calls to send()
    /// but not yet transmitted to the network. This value resets to zero once all queued
    /// data has been sent. This value does not reset to zero when the connection is closed;
    /// if you keep calling send(), this will continue to climb.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn buffered_amount(&self) -> u64 {
        js!( return @{self}.bufferedAmount; ).try_into().unwrap()
    }

    /// Returns the extensions selected by the server. This is currently only the empty
    /// string or a list of extensions as negotiated by the connection.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn extensions(&self) -> String {
        js!( return @{self}.extensions; ).try_into().unwrap()
    }

    /// Returns a string indicating the name of the sub-protocol the server selected;
    /// this will be one of the strings specified in the protocols parameter when
    /// creating the WebSocket object.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn protocol(&self) -> String {
        js!( return @{self}.protocol; ).try_into().unwrap()
    }

    /// Returns the current state of the connection.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn ready_state(&self) -> SocketReadyState {
        js!( return @{self}.protocol; ).try_into().unwrap()
    }

    /// Returns the URL as resolved by the constructor. This is always an absolute URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
    pub fn url(&self) -> String {
        js!( return @{self}.url; ).try_into().unwrap()
    }

    /// Closes the WebSocket connection or connection attempt, if any. If the connection
    /// is already CLOSED, this method does nothing.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#close())
    pub fn close(&self) {
        js!( @(no_return) @{self}.close(); );
    }

    /// Closes the WebSocket connection or connection attempt, if any. If the connection
    /// is already CLOSED, this method does nothing.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#close())
    pub fn close_with_status(&self, code: SocketCloseCode, reason: &str) -> Result<(), CloseError> {
        js_try!( @(no_return)
            @{self}.close(@{code.0}, @{reason});
        ).unwrap()
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_text(&self, text: &str) {
        js!( @(no_return) @{self}.send(@{text}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_blob(&self, blob: &Blob) {
        js!( @(no_return) @{self}.send(@{blob}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_array_buffer(&self, array_buffer: &ArrayBuffer) {
        js!( @(no_return) @{self}.send(@{array_buffer}); );
    }

    /// Enqueues the specified data to be transmitted to the server over the WebSocket
    /// connection, increasing the value of bufferedAmount by the number of bytes needed
    /// to contain the data. If the data can't be sent (for example, because it needs to
    /// be buffered but the buffer is full), the socket is closed automatically.
    pub fn send_bytes(&self, bytes: &[u8]) {
        js!( @(no_return) @{self}.send(@{ UnsafeTypedArray(bytes) }); );
    }
}

/// Errors thrown by `WebSocket::new`.
error_enum_boilerplate! {
    CreationError,
    SecurityError, SyntaxError
}

/// Errors thrown by `WebSocket::close_with_status`.
error_enum_boilerplate! {
    CloseError,
    InvalidAccessError, SyntaxError
}

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

    #[test]
    fn test_close_codes() {
        assert_eq!(&format!("{:?}", SocketCloseCode::NORMAL_CLOSURE), "SocketCloseCode::NORMAL_CLOSURE");
        assert_eq!(&format!("{:?}", SocketCloseCode::GOING_AWAY), "SocketCloseCode::GOING_AWAY");
        assert_eq!(&format!("{:?}", SocketCloseCode(1000)), "SocketCloseCode::NORMAL_CLOSURE");
        assert_eq!(&format!("{:?}", SocketCloseCode(3001)), "SocketCloseCode(3001)");
    }
}

#[cfg(all(test, feature = "web_test"))]
mod web_tests {
    use super::*;

    #[test]
    fn test_new() {
        assert!(WebSocket::new("ws://localhost").is_ok());

        match WebSocket::new("bad url") {
            Err(CreationError::SyntaxError(_)) => (),
            v => panic!("expected SyntaxError, got {:?}", v),
        }
    }

    #[test]
    fn test_close() {
        let socket = WebSocket::new("ws://localhost").unwrap();

        socket.close();

        assert!(socket.close_with_status( SocketCloseCode::NORMAL_CLOSURE, "closed" ).is_ok());

        // Invalid close code
        match socket.close_with_status( SocketCloseCode(12345), "closed" ) {
            Err(CloseError::InvalidAccessError(_)) => (),
            v => panic!("expected InvalidAccessError, got {:?}", v),
        }

        // Close reason too long (>123 bytes according to spec)
        match socket.close_with_status(
            SocketCloseCode::NORMAL_CLOSURE,
            &(0..200).map(|_| "X").collect::<String>()
        ) {
            Err(CloseError::SyntaxError(_)) => (),
            v => panic!("expected SyntaxError, got {:?}", v),
        }
    }
}
<|endoftext|>


<commit_before>//! The Tokio runtime.
//!
//! Unlike other Rust programs, asynchronous applications require
//! runtime support. In particular, the following runtime services are
//! necessary:
//!
//! * An **I/O event loop**, called the driver, which drives I/O resources and
//!   dispatches I/O events to tasks that depend on them.
//! * A **scheduler** to execute [tasks] that use these I/O resources.
//! * A **timer** for scheduling work to run after a set period of time.
//!
//! Tokio's [`Runtime`] bundles all of these services as a single type, allowing
//! them to be started, shut down, and configured together. However, most
//! applications won't need to use [`Runtime`] directly. Instead, they can
//! use the [`tokio::main`] attribute macro, which creates a [`Runtime`] under
//! the hood.
//!
//! # Usage
//!
//! Most applications will use the [`tokio::main`] attribute macro.
//!
//! ```no_run
//! use tokio::net::TcpListener;
//! use tokio::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
//!
//!     loop {
//!         let (mut socket, _) = listener.accept().await?;
//!
//!         tokio::spawn(async move {
//!             let mut buf = [0; 1024];
//!
//!             // In a loop, read data from the socket and write the data back.
//!             loop {
//!                 let n = match socket.read(&mut buf).await {
//!                     // socket closed
//!                     Ok(n) if n == 0 => return,
//!                     Ok(n) => n,
//!                     Err(e) => {
//!                         println!("failed to read from socket; err = {:?}", e);
//!                         return;
//!                     }
//!                 };
//!
//!                 // Write the data back
//!                 if let Err(e) = socket.write_all(&buf[0..n]).await {
//!                     println!("failed to write to socket; err = {:?}", e);
//!                     return;
//!                 }
//!             }
//!         });
//!     }
//! }
//! ```
//!
//! From within the context of the runtime, additional tasks are spawned using
//! the [`tokio::spawn`] function. Futures spawned using this function will be
//! executed on the same thread pool used by the [`Runtime`].
//!
//! A [`Runtime`] instance can also be used directly.
//!
//! ```no_run
//! use tokio::net::TcpListener;
//! use tokio::prelude::*;
//! use tokio::runtime::Runtime;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Create the runtime
//!     let mut rt = Runtime::new()?;
//!
//!     // Spawn the root task
//!     rt.block_on(async {
//!         let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
//!
//!         loop {
//!             let (mut socket, _) = listener.accept().await?;
//!
//!             tokio::spawn(async move {
//!                 let mut buf = [0; 1024];
//!
//!                 // In a loop, read data from the socket and write the data back.
//!                 loop {
//!                     let n = match socket.read(&mut buf).await {
//!                         // socket closed
//!                         Ok(n) if n == 0 => return,
//!                         Ok(n) => n,
//!                         Err(e) => {
//!                             println!("failed to read from socket; err = {:?}", e);
//!                             return;
//!                         }
//!                     };
//!
//!                     // Write the data back
//!                     if let Err(e) = socket.write_all(&buf[0..n]).await {
//!                         println!("failed to write to socket; err = {:?}", e);
//!                         return;
//!                     }
//!                 }
//!             });
//!         }
//!     })
//! }
//! ```
//!
//! ## Runtime Configurations
//!
//! Tokio provides multiple task scheding strategies, suitable for different
//! applications. The [runtime builder] or `#[tokio::main]` attribute may be
//! used to select which scheduler to use.
//!
//! #### Basic Scheduler
//!
//! The basic scheduler provides a _single-threaded_ future executor. All tasks
//! will be created and executed on the current thread. The basic scheduler
//! requires the `rt-core` feature flag, and can be selected using the
//! [`Builder::basic_scheduler`] method:
//! ```
//! use tokio::runtime;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let basic_rt = runtime::Builder::new()
//!     .basic_scheduler()
//!     .build()?;
//! # Ok(()) }
//! ```
//!
//! If the `rt-core` feature is enabled and `rt-threaded` is not,
//! [`Runtime::new`] will return a basic scheduler runtime by default.
//!
//! #### Threaded Scheduler
//!
//! The threaded scheduler executes futures on a _thread pool_, using a
//! work-stealing strategy. By default, it will start a worker thread for each
//! CPU core available on the system. This tends to be the ideal configurations
//! for most applications. The threaded scheduler requires the `rt-threaded` feature
//! flag, and can be selected using the  [`Builder::threaded_scheduler`] method:
//! ```
//! use tokio::runtime;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let threaded_rt = runtime::Builder::new()
//!     .threaded_scheduler()
//!     .build()?;
//! # Ok(()) }
//! ```
//!
//! If the `rt-threaded` feature flag is enabled, [`Runtime::new`] will return a
//! basic scheduler runtime by default.
//!
//! Most applications should use the threaded scheduler, except in some niche
//! use-cases, such as when running only a single thread is required.
//!
//! #### Resource drivers
//!
//! When configuring a runtime by hand, no resource drivers are enabled by
//! default. In this case, attempting to use networking types or time types will
//! fail. In order to enable these types, the resource drivers must be enabled.
//! This is done with [`Builder::enable_io`] and [`Builder::enable_time`]. As a
//! shorthand, [`Builder::enable_all`] enables both resource drivers.
//!
//! ## Lifetime of spawned threads
//!
//! The runtime may spawn threads depending on its configuration and usage. The
//! threaded scheduler spawns threads to schedule tasks and calls to
//! `spawn_blocking` spawn threads to run blocking operations.
//!
//! While the `Runtime` is active, threads may shutdown after periods of being
//! idle. Once `Runtime` is dropped, all runtime threads are forcibly shutdown.
//! Any tasks that have not yet completed will be dropped.
//!
//! [tasks]: crate::task
//! [`Runtime`]: Runtime
//! [`tokio::spawn`]: crate::spawn
//! [`tokio::main`]: ../attr.main.html
//! [runtime builder]: crate::runtime::Builder
//! [`Runtime::new`]: crate::runtime::Runtime::new
//! [`Builder::basic_scheduler`]: crate::runtime::Builder::basic_scheduler
//! [`Builder::threaded_scheduler`]: crate::runtime::Builder::threaded_scheduler
//! [`Builder::enable_io`]: crate::runtime::Builder::enable_io
//! [`Builder::enable_time`]: crate::runtime::Builder::enable_time
//! [`Builder::enable_all`]: crate::runtime::Builder::enable_all

// At the top due to macros
#[cfg(test)]
#[macro_use]
mod tests;
pub(crate) mod context;

cfg_rt_core! {
    mod basic_scheduler;
    use basic_scheduler::BasicScheduler;
}

mod blocking;
use blocking::BlockingPool;

cfg_blocking_impl! {
    pub(crate) use blocking::spawn_blocking;
}

mod builder;
pub use self::builder::Builder;

pub(crate) mod enter;
use self::enter::enter;

mod handle;
pub use self::handle::Handle;

mod io;

cfg_rt_threaded! {
    mod park;
    use park::{Parker, Unparker};
}

mod shell;
use self::shell::Shell;

mod spawner;
use self::spawner::Spawner;

mod time;

cfg_rt_threaded! {
    pub(crate) mod thread_pool;
    use self::thread_pool::ThreadPool;
}

cfg_rt_core! {
    use crate::task::JoinHandle;
}

use std::future::Future;

/// The Tokio runtime.
///
/// The runtime provides an I/O [driver], task scheduler, [timer], and blocking
/// pool, necessary for running asynchronous tasks.
///
/// Instances of `Runtime` can be created using [`new`] or [`Builder`]. However,
/// most users will use the `#[tokio::main]` annotation on their entry point instead.
///
/// See [module level][mod] documentation for more details.
///
/// # Shutdown
///
/// Shutting down the runtime is done by dropping the value. The current thread
/// will block until the shut down operation has completed.
///
/// * Drain any scheduled work queues.
/// * Drop any futures that have not yet completed.
/// * Drop the reactor.
///
/// Once the reactor has dropped, any outstanding I/O resources bound to
/// that reactor will no longer function. Calling any method on them will
/// result in an error.
///
/// [driver]: crate::io::driver
/// [timer]: crate::time
/// [mod]: index.html
/// [`new`]: #method.new
/// [`Builder`]: struct.Builder.html
/// [`tokio::run`]: fn.run.html
#[derive(Debug)]
pub struct Runtime {
    /// Task executor
    kind: Kind,

    /// Handle to runtime, also contains driver handles
    handle: Handle,

    /// Blocking pool handle, used to signal shutdown
    blocking_pool: BlockingPool,
}

/// The runtime executor is either a thread-pool or a current-thread executor.
#[derive(Debug)]
enum Kind {
    /// Not able to execute concurrent tasks. This variant is mostly used to get
    /// access to the driver handles.
    Shell(Shell),

    /// Execute all tasks on the current-thread.
    #[cfg(feature = "rt-core")]
    Basic(BasicScheduler<time::Driver>),

    /// Execute tasks across multiple threads.
    #[cfg(feature = "rt-threaded")]
    ThreadPool(ThreadPool),
}

/// After thread starts / before thread stops
type Callback = std::sync::Arc<dyn Fn() + Send + Sync>;

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// This results in a scheduler, I/O driver, and time driver being
    /// initialized. The type of scheduler used depends on what feature flags
    /// are enabled: if the `rt-threaded` feature is enabled, the [threaded
    /// scheduler] is used, while if only the `rt-core` feature is enabled, the
    /// [basic scheduler] is used instead.
    ///
    /// If the threaded scheduler is selected, it will not spawn
    /// any worker threads until it needs to, i.e. tasks are scheduled to run.
    ///
    /// Most applications will not need to call this function directly. Instead,
    /// they will use the  [`#[tokio::main]` attribute][main]. When more complex
    /// configuration is necessary, the [runtime builder] may be used.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// # Examples
    ///
    /// Creating a new `Runtime` with default configuration values.
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    /// ```
    ///
    /// [mod]: index.html
    /// [main]: ../../tokio_macros/attr.main.html
    /// [threaded scheduler]: index.html#threaded-scheduler
    /// [basic scheduler]: index.html#basic-scheduler
    /// [runtime builder]: crate::runtime::Builder
    pub fn new() -> io::Result<Self> {
        #[cfg(feature = "rt-threaded")]
        let ret = Builder::new().threaded_scheduler().enable_all().build();

        #[cfg(all(not(feature = "rt-threaded"), feature = "rt-core"))]
        let ret = Builder::new().basic_scheduler().enable_all().build();

        #[cfg(not(feature = "rt-core"))]
        let ret = Builder::new().enable_all().build();

        ret
    }

    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let rt = Runtime::new().unwrap();
    ///
    /// // Spawn a future onto the runtime
    /// rt.spawn(async {
    ///     println!("now running on a worker thread");
    /// });
    /// # }
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    #[cfg(feature = "rt-core")]
    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        match &self.kind {
            Kind::Shell(_) => panic!("task execution disabled"),
            #[cfg(feature = "rt-threaded")]
            Kind::ThreadPool(exec) => exec.spawn(future),
            Kind::Basic(exec) => exec.spawn(future),
        }
    }

    /// Run a future to completion on the Tokio runtime. This is the runtime's
    /// entry point.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, and yielding its resolved result. Any tasks or timers which
    /// the future spawns internally will be executed on the runtime.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on<F: Future>(&mut self, future: F) -> F::Output {
        let kind = &mut self.kind;

        self.handle.enter(|| match kind {
            Kind::Shell(exec) => exec.block_on(future),
            #[cfg(feature = "rt-core")]
            Kind::Basic(exec) => exec.block_on(future),
            #[cfg(feature = "rt-threaded")]
            Kind::ThreadPool(exec) => exec.block_on(future),
        })
    }

    /// Enter the runtime context
    pub fn enter<F, R>(&self, f: F) -> R
    where
        F: FnOnce() -> R,
    {
        self.handle.enter(f)
    }

    /// Return a handle to the runtime's spawner.
    ///
    /// The returned handle can be used to spawn tasks that run on this runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let handle = rt.handle();
    ///
    /// handle.spawn(async { println!("hello"); });
    /// ```
    pub fn handle(&self) -> &Handle {
        &self.handle
    }
}
<commit_msg>docs: fix runtime creation doc in tokio::runtime (#2073)<commit_after>//! The Tokio runtime.
//!
//! Unlike other Rust programs, asynchronous applications require
//! runtime support. In particular, the following runtime services are
//! necessary:
//!
//! * An **I/O event loop**, called the driver, which drives I/O resources and
//!   dispatches I/O events to tasks that depend on them.
//! * A **scheduler** to execute [tasks] that use these I/O resources.
//! * A **timer** for scheduling work to run after a set period of time.
//!
//! Tokio's [`Runtime`] bundles all of these services as a single type, allowing
//! them to be started, shut down, and configured together. However, most
//! applications won't need to use [`Runtime`] directly. Instead, they can
//! use the [`tokio::main`] attribute macro, which creates a [`Runtime`] under
//! the hood.
//!
//! # Usage
//!
//! Most applications will use the [`tokio::main`] attribute macro.
//!
//! ```no_run
//! use tokio::net::TcpListener;
//! use tokio::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
//!
//!     loop {
//!         let (mut socket, _) = listener.accept().await?;
//!
//!         tokio::spawn(async move {
//!             let mut buf = [0; 1024];
//!
//!             // In a loop, read data from the socket and write the data back.
//!             loop {
//!                 let n = match socket.read(&mut buf).await {
//!                     // socket closed
//!                     Ok(n) if n == 0 => return,
//!                     Ok(n) => n,
//!                     Err(e) => {
//!                         println!("failed to read from socket; err = {:?}", e);
//!                         return;
//!                     }
//!                 };
//!
//!                 // Write the data back
//!                 if let Err(e) = socket.write_all(&buf[0..n]).await {
//!                     println!("failed to write to socket; err = {:?}", e);
//!                     return;
//!                 }
//!             }
//!         });
//!     }
//! }
//! ```
//!
//! From within the context of the runtime, additional tasks are spawned using
//! the [`tokio::spawn`] function. Futures spawned using this function will be
//! executed on the same thread pool used by the [`Runtime`].
//!
//! A [`Runtime`] instance can also be used directly.
//!
//! ```no_run
//! use tokio::net::TcpListener;
//! use tokio::prelude::*;
//! use tokio::runtime::Runtime;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Create the runtime
//!     let mut rt = Runtime::new()?;
//!
//!     // Spawn the root task
//!     rt.block_on(async {
//!         let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
//!
//!         loop {
//!             let (mut socket, _) = listener.accept().await?;
//!
//!             tokio::spawn(async move {
//!                 let mut buf = [0; 1024];
//!
//!                 // In a loop, read data from the socket and write the data back.
//!                 loop {
//!                     let n = match socket.read(&mut buf).await {
//!                         // socket closed
//!                         Ok(n) if n == 0 => return,
//!                         Ok(n) => n,
//!                         Err(e) => {
//!                             println!("failed to read from socket; err = {:?}", e);
//!                             return;
//!                         }
//!                     };
//!
//!                     // Write the data back
//!                     if let Err(e) = socket.write_all(&buf[0..n]).await {
//!                         println!("failed to write to socket; err = {:?}", e);
//!                         return;
//!                     }
//!                 }
//!             });
//!         }
//!     })
//! }
//! ```
//!
//! ## Runtime Configurations
//!
//! Tokio provides multiple task scheding strategies, suitable for different
//! applications. The [runtime builder] or `#[tokio::main]` attribute may be
//! used to select which scheduler to use.
//!
//! #### Basic Scheduler
//!
//! The basic scheduler provides a _single-threaded_ future executor. All tasks
//! will be created and executed on the current thread. The basic scheduler
//! requires the `rt-core` feature flag, and can be selected using the
//! [`Builder::basic_scheduler`] method:
//! ```
//! use tokio::runtime;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let basic_rt = runtime::Builder::new()
//!     .basic_scheduler()
//!     .build()?;
//! # Ok(()) }
//! ```
//!
//! If the `rt-core` feature is enabled and `rt-threaded` is not,
//! [`Runtime::new`] will return a basic scheduler runtime by default.
//!
//! #### Threaded Scheduler
//!
//! The threaded scheduler executes futures on a _thread pool_, using a
//! work-stealing strategy. By default, it will start a worker thread for each
//! CPU core available on the system. This tends to be the ideal configurations
//! for most applications. The threaded scheduler requires the `rt-threaded` feature
//! flag, and can be selected using the  [`Builder::threaded_scheduler`] method:
//! ```
//! use tokio::runtime;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let threaded_rt = runtime::Builder::new()
//!     .threaded_scheduler()
//!     .build()?;
//! # Ok(()) }
//! ```
//!
//! If the `rt-threaded` feature flag is enabled, [`Runtime::new`] will return a
//! threaded scheduler runtime by default.
//!
//! Most applications should use the threaded scheduler, except in some niche
//! use-cases, such as when running only a single thread is required.
//!
//! #### Resource drivers
//!
//! When configuring a runtime by hand, no resource drivers are enabled by
//! default. In this case, attempting to use networking types or time types will
//! fail. In order to enable these types, the resource drivers must be enabled.
//! This is done with [`Builder::enable_io`] and [`Builder::enable_time`]. As a
//! shorthand, [`Builder::enable_all`] enables both resource drivers.
//!
//! ## Lifetime of spawned threads
//!
//! The runtime may spawn threads depending on its configuration and usage. The
//! threaded scheduler spawns threads to schedule tasks and calls to
//! `spawn_blocking` spawn threads to run blocking operations.
//!
//! While the `Runtime` is active, threads may shutdown after periods of being
//! idle. Once `Runtime` is dropped, all runtime threads are forcibly shutdown.
//! Any tasks that have not yet completed will be dropped.
//!
//! [tasks]: crate::task
//! [`Runtime`]: Runtime
//! [`tokio::spawn`]: crate::spawn
//! [`tokio::main`]: ../attr.main.html
//! [runtime builder]: crate::runtime::Builder
//! [`Runtime::new`]: crate::runtime::Runtime::new
//! [`Builder::basic_scheduler`]: crate::runtime::Builder::basic_scheduler
//! [`Builder::threaded_scheduler`]: crate::runtime::Builder::threaded_scheduler
//! [`Builder::enable_io`]: crate::runtime::Builder::enable_io
//! [`Builder::enable_time`]: crate::runtime::Builder::enable_time
//! [`Builder::enable_all`]: crate::runtime::Builder::enable_all

// At the top due to macros
#[cfg(test)]
#[macro_use]
mod tests;
pub(crate) mod context;

cfg_rt_core! {
    mod basic_scheduler;
    use basic_scheduler::BasicScheduler;
}

mod blocking;
use blocking::BlockingPool;

cfg_blocking_impl! {
    pub(crate) use blocking::spawn_blocking;
}

mod builder;
pub use self::builder::Builder;

pub(crate) mod enter;
use self::enter::enter;

mod handle;
pub use self::handle::Handle;

mod io;

cfg_rt_threaded! {
    mod park;
    use park::{Parker, Unparker};
}

mod shell;
use self::shell::Shell;

mod spawner;
use self::spawner::Spawner;

mod time;

cfg_rt_threaded! {
    pub(crate) mod thread_pool;
    use self::thread_pool::ThreadPool;
}

cfg_rt_core! {
    use crate::task::JoinHandle;
}

use std::future::Future;

/// The Tokio runtime.
///
/// The runtime provides an I/O [driver], task scheduler, [timer], and blocking
/// pool, necessary for running asynchronous tasks.
///
/// Instances of `Runtime` can be created using [`new`] or [`Builder`]. However,
/// most users will use the `#[tokio::main]` annotation on their entry point instead.
///
/// See [module level][mod] documentation for more details.
///
/// # Shutdown
///
/// Shutting down the runtime is done by dropping the value. The current thread
/// will block until the shut down operation has completed.
///
/// * Drain any scheduled work queues.
/// * Drop any futures that have not yet completed.
/// * Drop the reactor.
///
/// Once the reactor has dropped, any outstanding I/O resources bound to
/// that reactor will no longer function. Calling any method on them will
/// result in an error.
///
/// [driver]: crate::io::driver
/// [timer]: crate::time
/// [mod]: index.html
/// [`new`]: #method.new
/// [`Builder`]: struct.Builder.html
/// [`tokio::run`]: fn.run.html
#[derive(Debug)]
pub struct Runtime {
    /// Task executor
    kind: Kind,

    /// Handle to runtime, also contains driver handles
    handle: Handle,

    /// Blocking pool handle, used to signal shutdown
    blocking_pool: BlockingPool,
}

/// The runtime executor is either a thread-pool or a current-thread executor.
#[derive(Debug)]
enum Kind {
    /// Not able to execute concurrent tasks. This variant is mostly used to get
    /// access to the driver handles.
    Shell(Shell),

    /// Execute all tasks on the current-thread.
    #[cfg(feature = "rt-core")]
    Basic(BasicScheduler<time::Driver>),

    /// Execute tasks across multiple threads.
    #[cfg(feature = "rt-threaded")]
    ThreadPool(ThreadPool),
}

/// After thread starts / before thread stops
type Callback = std::sync::Arc<dyn Fn() + Send + Sync>;

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// This results in a scheduler, I/O driver, and time driver being
    /// initialized. The type of scheduler used depends on what feature flags
    /// are enabled: if the `rt-threaded` feature is enabled, the [threaded
    /// scheduler] is used, while if only the `rt-core` feature is enabled, the
    /// [basic scheduler] is used instead.
    ///
    /// If the threaded scheduler is selected, it will not spawn
    /// any worker threads until it needs to, i.e. tasks are scheduled to run.
    ///
    /// Most applications will not need to call this function directly. Instead,
    /// they will use the  [`#[tokio::main]` attribute][main]. When more complex
    /// configuration is necessary, the [runtime builder] may be used.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// # Examples
    ///
    /// Creating a new `Runtime` with default configuration values.
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    /// ```
    ///
    /// [mod]: index.html
    /// [main]: ../../tokio_macros/attr.main.html
    /// [threaded scheduler]: index.html#threaded-scheduler
    /// [basic scheduler]: index.html#basic-scheduler
    /// [runtime builder]: crate::runtime::Builder
    pub fn new() -> io::Result<Self> {
        #[cfg(feature = "rt-threaded")]
        let ret = Builder::new().threaded_scheduler().enable_all().build();

        #[cfg(all(not(feature = "rt-threaded"), feature = "rt-core"))]
        let ret = Builder::new().basic_scheduler().enable_all().build();

        #[cfg(not(feature = "rt-core"))]
        let ret = Builder::new().enable_all().build();

        ret
    }

    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let rt = Runtime::new().unwrap();
    ///
    /// // Spawn a future onto the runtime
    /// rt.spawn(async {
    ///     println!("now running on a worker thread");
    /// });
    /// # }
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    #[cfg(feature = "rt-core")]
    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        match &self.kind {
            Kind::Shell(_) => panic!("task execution disabled"),
            #[cfg(feature = "rt-threaded")]
            Kind::ThreadPool(exec) => exec.spawn(future),
            Kind::Basic(exec) => exec.spawn(future),
        }
    }

    /// Run a future to completion on the Tokio runtime. This is the runtime's
    /// entry point.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, and yielding its resolved result. Any tasks or timers which
    /// the future spawns internally will be executed on the runtime.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on<F: Future>(&mut self, future: F) -> F::Output {
        let kind = &mut self.kind;

        self.handle.enter(|| match kind {
            Kind::Shell(exec) => exec.block_on(future),
            #[cfg(feature = "rt-core")]
            Kind::Basic(exec) => exec.block_on(future),
            #[cfg(feature = "rt-threaded")]
            Kind::ThreadPool(exec) => exec.block_on(future),
        })
    }

    /// Enter the runtime context
    pub fn enter<F, R>(&self, f: F) -> R
    where
        F: FnOnce() -> R,
    {
        self.handle.enter(f)
    }

    /// Return a handle to the runtime's spawner.
    ///
    /// The returned handle can be used to spawn tasks that run on this runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let handle = rt.handle();
    ///
    /// handle.spawn(async { println!("hello"); });
    /// ```
    pub fn handle(&self) -> &Handle {
        &self.handle
    }
}
<|endoftext|>


<commit_before>//! Helper functions for dealing with sets or lists of parcels.

use {Parcel, Error, TryFromIntError, Settings};
use types::Integer;

use std::io::prelude::*;

/// The integer type that we will use to send length prefixes.
pub type SizeType = u32;

/// Reads a specified number of items from a stream.
pub fn read_items<T>(item_count: usize,
                     read: &mut Read,
                     settings: &Settings)
    -> Result<impl Iterator<Item=T>, Error>
    where T: Parcel {
    let mut elements = Vec::with_capacity(item_count);

    for _ in 0..item_count {
        let element = T::read(read, settings)?;
        elements.push(element);
    }
    Ok(elements.into_iter())
}

/// Writes an iterator of parcels to the stream.
///
/// Does not include a length prefix.
pub fn write_items<'a,T>(write: &mut Write,
                         items: impl IntoIterator<Item=&'a T>,
                         settings: &Settings)
    -> Result<(), Error>
    where T: Parcel + 'a {
    for item in items.into_iter() {
        item.write(write, settings)?;
    }
    Ok(())

}

/// Reads a length-prefixed list from a stream.
pub fn read_list<T>(read: &mut Read,
                    settings: &Settings)
    -> Result<Vec<T>, Error>
    where T: Parcel {
    self::read_list_ext::<SizeType, T>(read, settings)
}

/// Writes a length-prefixed list to a stream.
pub fn write_list<'a,T,I>(write: &mut Write,
                          elements: I,
                          settings: &Settings)
    -> Result<(), Error>
    where T: Parcel+'a,
          I: IntoIterator<Item=&'a T> {
    self::write_list_ext::<SizeType, T, I>(write, elements, settings)
}

/// Reads a length-prefixed list from a stream.
pub fn read_list_ext<S,T>(read: &mut Read,
                          settings: &Settings)
    -> Result<Vec<T>, Error>
    where S: Integer,
          T: Parcel {
    let size = S::read(read, settings)?;
    let size: usize = size.to_usize().ok_or(TryFromIntError{ })?;

    read_items(size, read, settings).map(|i| i.collect())
}

/// Writes a length-prefixed list to a stream.
pub fn write_list_ext<'a,S,T,I>(write: &mut Write,
                                elements: I,
                                settings: &Settings)
    -> Result<(), Error>
    where S: Integer,
          T: Parcel+'a,
          I: IntoIterator<Item=&'a T> {
    let elements: Vec<_> = elements.into_iter().collect();
    let length = S::from_usize(elements.len()).ok_or(TryFromIntError{ })?;
    length.write(write, settings)?;

    write_items(write, elements.into_iter(), settings)?;

    Ok(())
}

<commit_msg>Add read_string helper to the util module<commit_after>//! Helper functions for dealing with sets or lists of parcels.

use {Parcel, Error, TryFromIntError, Settings};
use types::Integer;

use std::io::prelude::*;

/// The integer type that we will use to send length prefixes.
pub type SizeType = u32;

/// Reads a string of specified length from a stream.
pub fn read_string(byte_count: usize,
                   read: &mut Read,
                   settings: &Settings)
    -> Result<String, Error> {
    let bytes: Vec<u8> = read_items(byte_count, read, settings)?.collect();
    String::from_utf8(bytes).map_err(Into::into)
}

/// Reads a specified number of items from a stream.
pub fn read_items<T>(item_count: usize,
                     read: &mut Read,
                     settings: &Settings)
    -> Result<impl Iterator<Item=T>, Error>
    where T: Parcel {
    let mut elements = Vec::with_capacity(item_count);

    for _ in 0..item_count {
        let element = T::read(read, settings)?;
        elements.push(element);
    }
    Ok(elements.into_iter())
}

/// Writes an iterator of parcels to the stream.
///
/// Does not include a length prefix.
pub fn write_items<'a,T>(write: &mut Write,
                         items: impl IntoIterator<Item=&'a T>,
                         settings: &Settings)
    -> Result<(), Error>
    where T: Parcel + 'a {
    for item in items.into_iter() {
        item.write(write, settings)?;
    }
    Ok(())

}

/// Reads a length-prefixed list from a stream.
pub fn read_list<T>(read: &mut Read,
                    settings: &Settings)
    -> Result<Vec<T>, Error>
    where T: Parcel {
    self::read_list_ext::<SizeType, T>(read, settings)
}

/// Writes a length-prefixed list to a stream.
pub fn write_list<'a,T,I>(write: &mut Write,
                          elements: I,
                          settings: &Settings)
    -> Result<(), Error>
    where T: Parcel+'a,
          I: IntoIterator<Item=&'a T> {
    self::write_list_ext::<SizeType, T, I>(write, elements, settings)
}

/// Reads a length-prefixed list from a stream.
pub fn read_list_ext<S,T>(read: &mut Read,
                          settings: &Settings)
    -> Result<Vec<T>, Error>
    where S: Integer,
          T: Parcel {
    let size = S::read(read, settings)?;
    let size: usize = size.to_usize().ok_or(TryFromIntError{ })?;

    read_items(size, read, settings).map(|i| i.collect())
}

/// Writes a length-prefixed list to a stream.
pub fn write_list_ext<'a,S,T,I>(write: &mut Write,
                                elements: I,
                                settings: &Settings)
    -> Result<(), Error>
    where S: Integer,
          T: Parcel+'a,
          I: IntoIterator<Item=&'a T> {
    let elements: Vec<_> = elements.into_iter().collect();
    let length = S::from_usize(elements.len()).ok_or(TryFromIntError{ })?;
    length.write(write, settings)?;

    write_items(write, elements.into_iter(), settings)?;

    Ok(())
}

<|endoftext|>


<commit_before>use std::cmp;

// Note: There are different ways to implement ZipSlices.
// This version performed the best in benchmarks.
//
// I also implemented a version with three pointes (tptr, tend, uptr),
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
// but that was inferior to this solution.

/// An iterator which iterates two slices simultaneously.
///
/// `ZipSlices` acts like a double-ended `.zip()` iterator.
///
/// It was intended to be more efficient than `.zip()`, and it was, then
/// rustc changed how it optimizes so it can not promise improved performance
/// at this time.
///
/// Note that elements past the end of the shortest of the two slices are ignored.
///
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
#[derive(Clone)]
pub struct ZipSlices<T, U> {
    t: T,
    u: U,
    len: usize,
    index: usize,
}

impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> {
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end of the shortest of the two slices are ignored.
    #[inline(always)]
    pub fn new(a: &'a [A], b: &'b [B]) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end of the shortest of the two slices are ignored.
    #[inline(always)]
    pub fn from_slices(a: T, b: U) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> Iterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    type Item = (T::Item, U::Item);

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                let i = self.index;
                self.index += 1;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len - self.index;
        (len, Some(len))
    }
}

impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                self.len -= 1;
                let i = self.len;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }
}

impl<T, U> ExactSizeIterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{}

unsafe impl<T, U> Slice for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    type Item = (T::Item, U::Item);

    fn len(&self) -> usize {
        self.len - self.index
    }

    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
        (self.t.get_unchecked(i),
         self.u.get_unchecked(i))
    }
}

/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
///
/// Unsafe trait because:
///
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
pub unsafe trait Slice {
    /// The type of a reference to the slice's elements
    type Item;
    #[doc(hidden)]
    fn len(&self) -> usize;
    #[doc(hidden)]
    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
}

unsafe impl<'a, T> Slice for &'a [T] {
    type Item = &'a T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
        debug_assert!(i < self.len());
        (**self).get_unchecked(i)
    }
}

unsafe impl<'a, T> Slice for &'a mut [T] {
    type Item = &'a mut T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
        debug_assert!(i < self.len());
        // override the lifetime constraints of &mut &'a mut [T]
        (*(*self as *mut [T])).get_unchecked_mut(i)
    }
}

#[test]
fn zipslices() {

    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));

    let xs = [1, 2, 3, 4, 5, 6];
    let mut ys = [0; 6];
    for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
        *y = *x;
    }
    itertools::assert_equal(&xs, &ys);
}

<commit_msg>Update zipslice tests<commit_after>use std::cmp;

// Note: There are different ways to implement ZipSlices.
// This version performed the best in benchmarks.
//
// I also implemented a version with three pointes (tptr, tend, uptr),
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
// but that was inferior to this solution.

/// An iterator which iterates two slices simultaneously.
///
/// `ZipSlices` acts like a double-ended `.zip()` iterator.
///
/// It was intended to be more efficient than `.zip()`, and it was, then
/// rustc changed how it optimizes so it can not promise improved performance
/// at this time.
///
/// Note that elements past the end of the shortest of the two slices are ignored.
///
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
#[derive(Clone)]
pub struct ZipSlices<T, U> {
    t: T,
    u: U,
    len: usize,
    index: usize,
}

impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> {
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end of the shortest of the two slices are ignored.
    #[inline(always)]
    pub fn new(a: &'a [A], b: &'b [B]) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    /// Create a new `ZipSlices` from slices `a` and `b`.
    ///
    /// Act like a double-ended `.zip()` iterator, but more efficiently.
    ///
    /// Note that elements past the end of the shortest of the two slices are ignored.
    #[inline(always)]
    pub fn from_slices(a: T, b: U) -> Self {
        let minl = cmp::min(a.len(), b.len());
        ZipSlices {
            t: a,
            u: b,
            len: minl,
            index: 0,
        }
    }
}

impl<T, U> Iterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    type Item = (T::Item, U::Item);

    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                let i = self.index;
                self.index += 1;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len - self.index;
        (len, Some(len))
    }
}

impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    #[inline(always)]
    fn next_back(&mut self) -> Option<Self::Item> {
        unsafe {
            if self.index >= self.len {
                None
            } else {
                self.len -= 1;
                let i = self.len;
                Some((
                    self.t.get_unchecked(i),
                    self.u.get_unchecked(i)))
            }
        }
    }
}

impl<T, U> ExactSizeIterator for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{}

unsafe impl<T, U> Slice for ZipSlices<T, U>
    where T: Slice,
          U: Slice
{
    type Item = (T::Item, U::Item);

    fn len(&self) -> usize {
        self.len - self.index
    }

    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
        (self.t.get_unchecked(i),
         self.u.get_unchecked(i))
    }
}

/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
///
/// Unsafe trait because:
///
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
pub unsafe trait Slice {
    /// The type of a reference to the slice's elements
    type Item;
    #[doc(hidden)]
    fn len(&self) -> usize;
    #[doc(hidden)]
    unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
}

unsafe impl<'a, T> Slice for &'a [T] {
    type Item = &'a T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
        debug_assert!(i < self.len());
        (**self).get_unchecked(i)
    }
}

unsafe impl<'a, T> Slice for &'a mut [T] {
    type Item = &'a mut T;
    #[inline(always)]
    fn len(&self) -> usize { (**self).len() }
    #[inline(always)]
    unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
        debug_assert!(i < self.len());
        // override the lifetime constraints of &mut &'a mut [T]
        (*(*self as *mut [T])).get_unchecked_mut(i)
    }
}

#[test]
fn zipslices() {

    let xs = [1, 2, 3, 4, 5, 6];
    let ys = [1, 2, 3, 7];
    ::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));

    let xs = [1, 2, 3, 4, 5, 6];
    let mut ys = [0; 6];
    for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
        *y = *x;
    }
    ::itertools::assert_equal(&xs, &ys);
}

<|endoftext|>


<commit_before>use num_derive::FromPrimitive;
use std::str::FromStr;

#[repr(u8)]
#[derive(
    Debug, Eq, PartialEq, Hash, Copy, Clone, serde::Serialize, serde::Deserialize, FromPrimitive,
)]
pub enum KeyCode {
    LButton = 0x01,
    RButton = 0x02,
    Cancel = 0x03,
    MButton = 0x04,
    XButton1 = 0x05,
    XButton2 = 0x06,
    Back = 0x08,
    Tab = 0x09,
    Clear = 0x0C,
    Return = 0x0D,
    Shift = 0x10,
    Control = 0x11,
    Menu = 0x12,
    Pause = 0x13,
    Capital = 0x14,
    Kana = 0x15,
    Junja = 0x17,
    Final = 0x18,
    Kanji = 0x19,
    Escape = 0x1B,
    Convert = 0x1C,
    NonConvert = 0x1D,
    Accept = 0x1E,
    ModeChange = 0x1F,
    Space = 0x20,
    Prior = 0x21,
    Next = 0x22,
    End = 0x23,
    Home = 0x24,
    Left = 0x25,
    Up = 0x26,
    Right = 0x27,
    Down = 0x28,
    Select = 0x29,
    Print = 0x2A,
    Execute = 0x2B,
    Snapshot = 0x2C,
    Insert = 0x2D,
    Delete = 0x2E,
    Help = 0x2F,
    D0 = 0x30,
    D1 = 0x31,
    D2 = 0x32,
    D3 = 0x33,
    D4 = 0x34,
    D5 = 0x35,
    D6 = 0x36,
    D7 = 0x37,
    D8 = 0x38,
    D9 = 0x39,
    A = 0x41,
    B = 0x42,
    C = 0x43,
    D = 0x44,
    E = 0x45,
    F = 0x46,
    G = 0x47,
    H = 0x48,
    I = 0x49,
    J = 0x4A,
    K = 0x4B,
    L = 0x4C,
    M = 0x4D,
    N = 0x4E,
    O = 0x4F,
    P = 0x50,
    Q = 0x51,
    R = 0x52,
    S = 0x53,
    T = 0x54,
    U = 0x55,
    V = 0x56,
    W = 0x57,
    X = 0x58,
    Y = 0x59,
    Z = 0x5A,
    LeftWin = 0x5B,
    RightWin = 0x5C,
    Apps = 0x5D,
    Sleep = 0x5F,
    NumPad0 = 0x60,
    NumPad1 = 0x61,
    NumPad2 = 0x62,
    NumPad3 = 0x63,
    NumPad4 = 0x64,
    NumPad5 = 0x65,
    NumPad6 = 0x66,
    NumPad7 = 0x67,
    NumPad8 = 0x68,
    NumPad9 = 0x69,
    Multiply = 0x6A,
    Add = 0x6B,
    Separator = 0x6C,
    Subtract = 0x6D,
    Decimal = 0x6E,
    Divide = 0x6F,
    F1 = 0x70,
    F2 = 0x71,
    F3 = 0x72,
    F4 = 0x73,
    F5 = 0x74,
    F6 = 0x75,
    F7 = 0x76,
    F8 = 0x77,
    F9 = 0x78,
    F10 = 0x79,
    F11 = 0x7A,
    F12 = 0x7B,
    F13 = 0x7C,
    F14 = 0x7D,
    F15 = 0x7E,
    F16 = 0x7F,
    F17 = 0x80,
    F18 = 0x81,
    F19 = 0x82,
    F20 = 0x83,
    F21 = 0x84,
    F22 = 0x85,
    F23 = 0x86,
    F24 = 0x87,
    NumLock = 0x90,
    Scroll = 0x91,
    LeftShift = 0xA0,
    RightShift = 0xA1,
    LeftControl = 0xA2,
    RightControl = 0xA3,
    LeftMenu = 0xA4,
    RightMenu = 0xA5,
    BrowserBack = 0xA6,
    BrowserForward = 0xA7,
    BrowserRefresh = 0xA8,
    BrowserStop = 0xA9,
    BrowserSearch = 0xAA,
    BrowserFavorites = 0xAB,
    BrowserHome = 0xAC,
    VolumeMute = 0xAD,
    VolumeDown = 0xAE,
    VolumeUp = 0xAF,
    MediaNextTrack = 0xB0,
    MediaPrevTrack = 0xB1,
    MediaStop = 0xB2,
    MediaPlayPause = 0xB3,
    LaunchMail = 0xB4,
    LaunchMediaSelect = 0xB5,
    LaunchApp1 = 0xB6,
    LaunchApp2 = 0xB7,
    Oem1 = 0xBA,
    OemPlus = 0xBB,
    OemComma = 0xBC,
    OemMinus = 0xBD,
    OemPeriod = 0xBE,
    Oem2 = 0xBF,
    Oem3 = 0xC0,
    Oem4 = 0xDB,
    Oem5 = 0xDC,
    Oem6 = 0xDD,
    Oem7 = 0xDE,
    Oem8 = 0xDF,
    Oem102 = 0xE2,
    ProcessKey = 0xE5,
    Packet = 0xE7,
    Attn = 0xF6,
    CrSel = 0xF7,
    ExSel = 0xF8,
    ErEof = 0xF9,
    Play = 0xFA,
    Zoom = 0xFB,
    NoName = 0xFC,
    Pa1 = 0xFD,
    OemClear = 0xFE,
    /// Keys with no keycode mapping can produce this
    None = 0xFF,
}

impl FromStr for KeyCode {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::KeyCode::*;
        Ok(match s {
            "LButton" => LButton,
            "RButton" => RButton,
            "Cancel" => Cancel,
            "MButton" => MButton,
            "XButton1" => XButton1,
            "XButton2" => XButton2,
            "Back" => Back,
            "Tab" => Tab,
            "Clear" => Clear,
            "Return" => Return,
            "Shift" => Shift,
            "Control" => Control,
            "Menu" => Menu,
            "Pause" => Pause,
            "Capital" => Capital,
            "Kana" => Kana,
            "Junja" => Junja,
            "Final" => Final,
            "Kanji" => Kanji,
            "Escape" => Escape,
            "Convert" => Convert,
            "NonConvert" => NonConvert,
            "Accept" => Accept,
            "ModeChange" => ModeChange,
            "Space" => Space,
            "Prior" => Prior,
            "Next" => Next,
            "End" => End,
            "Home" => Home,
            "Left" => Left,
            "Up" => Up,
            "Right" => Right,
            "Down" => Down,
            "Select" => Select,
            "Print" => Print,
            "Execute" => Execute,
            "Snapshot" => Snapshot,
            "Insert" => Insert,
            "Delete" => Delete,
            "Help" => Help,
            "D0" => D0,
            "D1" => D1,
            "D2" => D2,
            "D3" => D3,
            "D4" => D4,
            "D5" => D5,
            "D6" => D6,
            "D7" => D7,
            "D8" => D8,
            "D9" => D9,
            "A" => A,
            "B" => B,
            "C" => C,
            "D" => D,
            "E" => E,
            "F" => F,
            "G" => G,
            "H" => H,
            "I" => I,
            "J" => J,
            "K" => K,
            "L" => L,
            "M" => M,
            "N" => N,
            "O" => O,
            "P" => P,
            "Q" => Q,
            "R" => R,
            "S" => S,
            "T" => T,
            "U" => U,
            "V" => V,
            "W" => W,
            "X" => X,
            "Y" => Y,
            "Z" => Z,
            "LeftWin" => LeftWin,
            "RightWin" => RightWin,
            "Apps" => Apps,
            "Sleep" => Sleep,
            "NumPad0" => NumPad0,
            "NumPad1" => NumPad1,
            "NumPad2" => NumPad2,
            "NumPad3" => NumPad3,
            "NumPad4" => NumPad4,
            "NumPad5" => NumPad5,
            "NumPad6" => NumPad6,
            "NumPad7" => NumPad7,
            "NumPad8" => NumPad8,
            "NumPad9" => NumPad9,
            "Multiply" => Multiply,
            "Add" => Add,
            "Separator" => Separator,
            "Subtract" => Subtract,
            "Decimal" => Decimal,
            "Divide" => Divide,
            "F1" => F1,
            "F2" => F2,
            "F3" => F3,
            "F4" => F4,
            "F5" => F5,
            "F6" => F6,
            "F7" => F7,
            "F8" => F8,
            "F9" => F9,
            "F10" => F10,
            "F11" => F11,
            "F12" => F12,
            "F13" => F13,
            "F14" => F14,
            "F15" => F15,
            "F16" => F16,
            "F17" => F17,
            "F18" => F18,
            "F19" => F19,
            "F20" => F20,
            "F21" => F21,
            "F22" => F22,
            "F23" => F23,
            "F24" => F24,
            "NumLock" => NumLock,
            "Scroll" => Scroll,
            "LeftShift" => LeftShift,
            "RightShift" => RightShift,
            "LeftControl" => LeftControl,
            "RightControl" => RightControl,
            "LeftMenu" => LeftMenu,
            "RightMenu" => RightMenu,
            "BrowserBack" => BrowserBack,
            "BrowserForward" => BrowserForward,
            "BrowserRefresh" => BrowserRefresh,
            "BrowserStop" => BrowserStop,
            "BrowserSearch" => BrowserSearch,
            "BrowserFavorites" => BrowserFavorites,
            "BrowserHome" => BrowserHome,
            "VolumeMute" => VolumeMute,
            "VolumeDown" => VolumeDown,
            "VolumeUp" => VolumeUp,
            "MediaNextTrack" => MediaNextTrack,
            "MediaPrevTrack" => MediaPrevTrack,
            "MediaStop" => MediaStop,
            "MediaPlayPause" => MediaPlayPause,
            "LaunchMail" => LaunchMail,
            "LaunchMediaSelect" => LaunchMediaSelect,
            "LaunchApp1" => LaunchApp1,
            "LaunchApp2" => LaunchApp2,
            "Oem1" => Oem1,
            "OemPlus" => OemPlus,
            "OemComma" => OemComma,
            "OemMinus" => OemMinus,
            "OemPeriod" => OemPeriod,
            "Oem2" => Oem2,
            "Oem3" => Oem3,
            "Oem4" => Oem4,
            "Oem5" => Oem5,
            "Oem6" => Oem6,
            "Oem7" => Oem7,
            "Oem8" => Oem8,
            "Oem102" => Oem102,
            "ProcessKey" => ProcessKey,
            "Packet" => Packet,
            "Attn" => Attn,
            "CrSel" => CrSel,
            "ExSel" => ExSel,
            "ErEof" => ErEof,
            "Play" => Play,
            "Zoom" => Zoom,
            "NoName" => NoName,
            "Pa1" => Pa1,
            "OemClear" => OemClear,
            _ => return Err(()),
        })
    }
}
<commit_msg>Renamed KeyCode::None to KeyCode::Unmapped since it clashes with Option::None<commit_after>use num_derive::FromPrimitive;
use std::str::FromStr;

#[repr(u8)]
#[derive(
    Debug, Eq, PartialEq, Hash, Copy, Clone, serde::Serialize, serde::Deserialize, FromPrimitive,
)]
pub enum KeyCode {
    LButton = 0x01,
    RButton = 0x02,
    Cancel = 0x03,
    MButton = 0x04,
    XButton1 = 0x05,
    XButton2 = 0x06,
    Back = 0x08,
    Tab = 0x09,
    Clear = 0x0C,
    Return = 0x0D,
    Shift = 0x10,
    Control = 0x11,
    Menu = 0x12,
    Pause = 0x13,
    Capital = 0x14,
    Kana = 0x15,
    Junja = 0x17,
    Final = 0x18,
    Kanji = 0x19,
    Escape = 0x1B,
    Convert = 0x1C,
    NonConvert = 0x1D,
    Accept = 0x1E,
    ModeChange = 0x1F,
    Space = 0x20,
    Prior = 0x21,
    Next = 0x22,
    End = 0x23,
    Home = 0x24,
    Left = 0x25,
    Up = 0x26,
    Right = 0x27,
    Down = 0x28,
    Select = 0x29,
    Print = 0x2A,
    Execute = 0x2B,
    Snapshot = 0x2C,
    Insert = 0x2D,
    Delete = 0x2E,
    Help = 0x2F,
    D0 = 0x30,
    D1 = 0x31,
    D2 = 0x32,
    D3 = 0x33,
    D4 = 0x34,
    D5 = 0x35,
    D6 = 0x36,
    D7 = 0x37,
    D8 = 0x38,
    D9 = 0x39,
    A = 0x41,
    B = 0x42,
    C = 0x43,
    D = 0x44,
    E = 0x45,
    F = 0x46,
    G = 0x47,
    H = 0x48,
    I = 0x49,
    J = 0x4A,
    K = 0x4B,
    L = 0x4C,
    M = 0x4D,
    N = 0x4E,
    O = 0x4F,
    P = 0x50,
    Q = 0x51,
    R = 0x52,
    S = 0x53,
    T = 0x54,
    U = 0x55,
    V = 0x56,
    W = 0x57,
    X = 0x58,
    Y = 0x59,
    Z = 0x5A,
    LeftWin = 0x5B,
    RightWin = 0x5C,
    Apps = 0x5D,
    Sleep = 0x5F,
    NumPad0 = 0x60,
    NumPad1 = 0x61,
    NumPad2 = 0x62,
    NumPad3 = 0x63,
    NumPad4 = 0x64,
    NumPad5 = 0x65,
    NumPad6 = 0x66,
    NumPad7 = 0x67,
    NumPad8 = 0x68,
    NumPad9 = 0x69,
    Multiply = 0x6A,
    Add = 0x6B,
    Separator = 0x6C,
    Subtract = 0x6D,
    Decimal = 0x6E,
    Divide = 0x6F,
    F1 = 0x70,
    F2 = 0x71,
    F3 = 0x72,
    F4 = 0x73,
    F5 = 0x74,
    F6 = 0x75,
    F7 = 0x76,
    F8 = 0x77,
    F9 = 0x78,
    F10 = 0x79,
    F11 = 0x7A,
    F12 = 0x7B,
    F13 = 0x7C,
    F14 = 0x7D,
    F15 = 0x7E,
    F16 = 0x7F,
    F17 = 0x80,
    F18 = 0x81,
    F19 = 0x82,
    F20 = 0x83,
    F21 = 0x84,
    F22 = 0x85,
    F23 = 0x86,
    F24 = 0x87,
    NumLock = 0x90,
    Scroll = 0x91,
    LeftShift = 0xA0,
    RightShift = 0xA1,
    LeftControl = 0xA2,
    RightControl = 0xA3,
    LeftMenu = 0xA4,
    RightMenu = 0xA5,
    BrowserBack = 0xA6,
    BrowserForward = 0xA7,
    BrowserRefresh = 0xA8,
    BrowserStop = 0xA9,
    BrowserSearch = 0xAA,
    BrowserFavorites = 0xAB,
    BrowserHome = 0xAC,
    VolumeMute = 0xAD,
    VolumeDown = 0xAE,
    VolumeUp = 0xAF,
    MediaNextTrack = 0xB0,
    MediaPrevTrack = 0xB1,
    MediaStop = 0xB2,
    MediaPlayPause = 0xB3,
    LaunchMail = 0xB4,
    LaunchMediaSelect = 0xB5,
    LaunchApp1 = 0xB6,
    LaunchApp2 = 0xB7,
    Oem1 = 0xBA,
    OemPlus = 0xBB,
    OemComma = 0xBC,
    OemMinus = 0xBD,
    OemPeriod = 0xBE,
    Oem2 = 0xBF,
    Oem3 = 0xC0,
    Oem4 = 0xDB,
    Oem5 = 0xDC,
    Oem6 = 0xDD,
    Oem7 = 0xDE,
    Oem8 = 0xDF,
    Oem102 = 0xE2,
    ProcessKey = 0xE5,
    Packet = 0xE7,
    Attn = 0xF6,
    CrSel = 0xF7,
    ExSel = 0xF8,
    ErEof = 0xF9,
    Play = 0xFA,
    Zoom = 0xFB,
    NoName = 0xFC,
    Pa1 = 0xFD,
    OemClear = 0xFE,
    /// Keys with no keycode mapping can produce this
    Unmapped = 0xFF,
}

impl FromStr for KeyCode {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::KeyCode::*;
        Ok(match s {
            "LButton" => LButton,
            "RButton" => RButton,
            "Cancel" => Cancel,
            "MButton" => MButton,
            "XButton1" => XButton1,
            "XButton2" => XButton2,
            "Back" => Back,
            "Tab" => Tab,
            "Clear" => Clear,
            "Return" => Return,
            "Shift" => Shift,
            "Control" => Control,
            "Menu" => Menu,
            "Pause" => Pause,
            "Capital" => Capital,
            "Kana" => Kana,
            "Junja" => Junja,
            "Final" => Final,
            "Kanji" => Kanji,
            "Escape" => Escape,
            "Convert" => Convert,
            "NonConvert" => NonConvert,
            "Accept" => Accept,
            "ModeChange" => ModeChange,
            "Space" => Space,
            "Prior" => Prior,
            "Next" => Next,
            "End" => End,
            "Home" => Home,
            "Left" => Left,
            "Up" => Up,
            "Right" => Right,
            "Down" => Down,
            "Select" => Select,
            "Print" => Print,
            "Execute" => Execute,
            "Snapshot" => Snapshot,
            "Insert" => Insert,
            "Delete" => Delete,
            "Help" => Help,
            "D0" => D0,
            "D1" => D1,
            "D2" => D2,
            "D3" => D3,
            "D4" => D4,
            "D5" => D5,
            "D6" => D6,
            "D7" => D7,
            "D8" => D8,
            "D9" => D9,
            "A" => A,
            "B" => B,
            "C" => C,
            "D" => D,
            "E" => E,
            "F" => F,
            "G" => G,
            "H" => H,
            "I" => I,
            "J" => J,
            "K" => K,
            "L" => L,
            "M" => M,
            "N" => N,
            "O" => O,
            "P" => P,
            "Q" => Q,
            "R" => R,
            "S" => S,
            "T" => T,
            "U" => U,
            "V" => V,
            "W" => W,
            "X" => X,
            "Y" => Y,
            "Z" => Z,
            "LeftWin" => LeftWin,
            "RightWin" => RightWin,
            "Apps" => Apps,
            "Sleep" => Sleep,
            "NumPad0" => NumPad0,
            "NumPad1" => NumPad1,
            "NumPad2" => NumPad2,
            "NumPad3" => NumPad3,
            "NumPad4" => NumPad4,
            "NumPad5" => NumPad5,
            "NumPad6" => NumPad6,
            "NumPad7" => NumPad7,
            "NumPad8" => NumPad8,
            "NumPad9" => NumPad9,
            "Multiply" => Multiply,
            "Add" => Add,
            "Separator" => Separator,
            "Subtract" => Subtract,
            "Decimal" => Decimal,
            "Divide" => Divide,
            "F1" => F1,
            "F2" => F2,
            "F3" => F3,
            "F4" => F4,
            "F5" => F5,
            "F6" => F6,
            "F7" => F7,
            "F8" => F8,
            "F9" => F9,
            "F10" => F10,
            "F11" => F11,
            "F12" => F12,
            "F13" => F13,
            "F14" => F14,
            "F15" => F15,
            "F16" => F16,
            "F17" => F17,
            "F18" => F18,
            "F19" => F19,
            "F20" => F20,
            "F21" => F21,
            "F22" => F22,
            "F23" => F23,
            "F24" => F24,
            "NumLock" => NumLock,
            "Scroll" => Scroll,
            "LeftShift" => LeftShift,
            "RightShift" => RightShift,
            "LeftControl" => LeftControl,
            "RightControl" => RightControl,
            "LeftMenu" => LeftMenu,
            "RightMenu" => RightMenu,
            "BrowserBack" => BrowserBack,
            "BrowserForward" => BrowserForward,
            "BrowserRefresh" => BrowserRefresh,
            "BrowserStop" => BrowserStop,
            "BrowserSearch" => BrowserSearch,
            "BrowserFavorites" => BrowserFavorites,
            "BrowserHome" => BrowserHome,
            "VolumeMute" => VolumeMute,
            "VolumeDown" => VolumeDown,
            "VolumeUp" => VolumeUp,
            "MediaNextTrack" => MediaNextTrack,
            "MediaPrevTrack" => MediaPrevTrack,
            "MediaStop" => MediaStop,
            "MediaPlayPause" => MediaPlayPause,
            "LaunchMail" => LaunchMail,
            "LaunchMediaSelect" => LaunchMediaSelect,
            "LaunchApp1" => LaunchApp1,
            "LaunchApp2" => LaunchApp2,
            "Oem1" => Oem1,
            "OemPlus" => OemPlus,
            "OemComma" => OemComma,
            "OemMinus" => OemMinus,
            "OemPeriod" => OemPeriod,
            "Oem2" => Oem2,
            "Oem3" => Oem3,
            "Oem4" => Oem4,
            "Oem5" => Oem5,
            "Oem6" => Oem6,
            "Oem7" => Oem7,
            "Oem8" => Oem8,
            "Oem102" => Oem102,
            "ProcessKey" => ProcessKey,
            "Packet" => Packet,
            "Attn" => Attn,
            "CrSel" => CrSel,
            "ExSel" => ExSel,
            "ErEof" => ErEof,
            "Play" => Play,
            "Zoom" => Zoom,
            "NoName" => NoName,
            "Pa1" => Pa1,
            "OemClear" => OemClear,
            _ => return Err(()),
        })
    }
}
<|endoftext|>