<commit_before>//! Error handling.

use std::{io, result, str, string};

use crate::protocol::{frame::coding::Data, Message};
use http::Response;
use thiserror::Error;

/// Result type of all Tungstenite library calls.
pub type Result<T> = result::Result<T, Error>;

/// Possible WebSocket errors.
#[derive(Error, Debug)]
pub enum Error {
    /// WebSocket connection closed normally. This informs you of the close.
    /// It's not an error as such and nothing wrong happened.
    ///
    /// This is returned as soon as the close handshake is finished (we have both sent and
    /// received a close frame) on the server end and as soon as the server has closed the
    /// underlying connection if this endpoint is a client.
    ///
    /// Thus when you receive this, it is safe to drop the underlying connection.
    ///
    /// Receiving this error means that the WebSocket object is not usable anymore and the
    /// only meaningful action with it is dropping it.
    #[error("Connection closed normally")]
    ConnectionClosed,
    /// Trying to work with already closed connection.
    ///
    /// Trying to read or write after receiving `ConnectionClosed` causes this.
    ///
    /// As opposed to `ConnectionClosed`, this indicates your code tries to operate on the
    /// connection when it really shouldn't anymore, so this really indicates a programmer
    /// error on your part.
    #[error("Trying to work with closed connection")]
    AlreadyClosed,
    /// Input-output error. Apart from WouldBlock, these are generally errors with the
    /// underlying connection and you should probably consider them fatal.
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    /// TLS error.
    ///
    /// Note that this error variant is enabled unconditionally even if no TLS feature is enabled,
    /// to provide a feature-agnostic API surface.
    #[error("TLS error: {0}")]
    Tls(#[from] TlsError),
    /// - When reading: buffer capacity exhausted.
    /// - When writing: your message is bigger than the configured max message size
    ///   (64MB by default).
    #[error("Space limit exceeded: {0}")]
    Capacity(CapacityError),
    /// Protocol violation.
    #[error("WebSocket protocol error: {0}")]
    Protocol(#[from] ProtocolError),
    /// Message send queue full.
    #[error("Send queue is full")]
    SendQueueFull(Message),
    /// UTF coding error.
    #[error("UTF-8 encoding error")]
    Utf8,
    /// Invalid URL.
    #[error("URL error: {0}")]
    Url(UrlError),
    /// HTTP error.
    #[error("HTTP error: {}", .0.status())]
    Http(Response<Option<String>>),
    /// HTTP format error.
    #[error("HTTP format error: {0}")]
    HttpFormat(#[from] http::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(_: str::Utf8Error) -> Self {
        Error::Utf8
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Self {
        Error::Utf8
    }
}

impl From<http::header::InvalidHeaderValue> for Error {
    fn from(err: http::header::InvalidHeaderValue) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::InvalidHeaderName> for Error {
    fn from(err: http::header::InvalidHeaderName) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::ToStrError> for Error {
    fn from(_: http::header::ToStrError) -> Self {
        Error::Utf8
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(err: http::uri::InvalidUri) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::status::InvalidStatusCode> for Error {
    fn from(err: http::status::InvalidStatusCode) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Self {
        match err {
            httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
            e => Error::Protocol(ProtocolError::HttparseError(e)),
        }
    }
}

/// Indicates the specific type/cause of a capacity error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum CapacityError {
    /// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
    #[error("Too many headers")]
    TooManyHeaders,
    /// Received header is too long.
    #[error("Header too long")]
    HeaderTooLong,
    /// Message is bigger than the maximum allowed size.
    #[error("Message too long: {size} > {max_size}")]
    MessageTooLong {
        /// The size of the message.
        size: usize,
        /// The maximum allowed message size.
        max_size: usize,
    },
    /// TCP buffer is full.
    #[error("Incoming TCP buffer is full")]
    TcpBufferFull,
}

/// Indicates the specific type/cause of a protocol error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum ProtocolError {
    /// Use of the wrong HTTP method (the WebSocket protocol requires the GET method be used).
    #[error("Unsupported HTTP method used - only GET is allowed")]
    WrongHttpMethod,
    /// Wrong HTTP version used (the WebSocket protocol requires version 1.1 or higher).
    #[error("HTTP version must be 1.1 or higher")]
    WrongHttpVersion,
    /// Missing `Connection: upgrade` HTTP header.
    #[error("No \"Connection: upgrade\" header")]
    MissingConnectionUpgradeHeader,
    /// Missing `Upgrade: websocket` HTTP header.
    #[error("No \"Upgrade: websocket\" header")]
    MissingUpgradeWebSocketHeader,
    /// Missing `Sec-WebSocket-Version: 13` HTTP header.
    #[error("No \"Sec-WebSocket-Version: 13\" header")]
    MissingSecWebSocketVersionHeader,
    /// Missing `Sec-WebSocket-Key` HTTP header.
    #[error("No \"Sec-WebSocket-Key\" header")]
    MissingSecWebSocketKey,
    /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
    #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
    SecWebSocketAcceptKeyMismatch,
    /// Garbage data encountered after client request.
    #[error("Junk after client request")]
    JunkAfterRequest,
    /// Custom responses must be unsuccessful.
    #[error("Custom response must not be successful")]
    CustomResponseSuccessful,
    /// No more data while still performing handshake.
    #[error("Handshake not finished")]
    HandshakeIncomplete,
    /// Wrapper around a [`httparse::Error`] value.
    #[error("httparse error: {0}")]
    HttparseError(#[from] httparse::Error),
    /// Not allowed to send after having sent a closing frame.
    #[error("Sending after closing is not allowed")]
    SendAfterClosing,
    /// Remote sent data after sending a closing frame.
    #[error("Remote sent after having closed")]
    ReceivedAfterClosing,
    /// Reserved bits in frame header are non-zero.
    #[error("Reserved bits are non-zero")]
    NonZeroReservedBits,
    /// The server must close the connection when an unmasked frame is received.
    #[error("Received an unmasked frame from client")]
    UnmaskedFrameFromClient,
    /// The client must close the connection when a masked frame is received.
    #[error("Received a masked frame from server")]
    MaskedFrameFromServer,
    /// Control frames must not be fragmented.
    #[error("Fragmented control frame")]
    FragmentedControlFrame,
    /// Control frames must have a payload of 125 bytes or less.
    #[error("Control frame too big (payload must be 125 bytes or less)")]
    ControlFrameTooBig,
    /// Type of control frame not recognised.
    #[error("Unknown control frame type: {0}")]
    UnknownControlFrameType(u8),
    /// Type of data frame not recognised.
    #[error("Unknown data frame type: {0}")]
    UnknownDataFrameType(u8),
    /// Received a continue frame despite there being nothing to continue.
    #[error("Continue frame but nothing to continue")]
    UnexpectedContinueFrame,
    /// Received data while waiting for more fragments.
    #[error("While waiting for more fragments received: {0}")]
    ExpectedFragment(Data),
    /// Connection closed without performing the closing handshake.
    #[error("Connection reset without closing handshake")]
    ResetWithoutClosingHandshake,
    /// Encountered an invalid opcode.
    #[error("Encountered invalid opcode: {0}")]
    InvalidOpcode(u8),
    /// The payload for the closing frame is invalid.
    #[error("Invalid close sequence")]
    InvalidCloseSequence,
}

/// Indicates the specific type/cause of URL error.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum UrlError {
    /// TLS is used despite not being compiled with the TLS feature enabled.
    #[error("TLS support not compiled in")]
    TlsFeatureNotEnabled,
    /// The URL does not include a host name.
    #[error("No host name in the URL")]
    NoHostName,
    /// Failed to connect with this URL.
    #[error("Unable to connect to {0}")]
    UnableToConnect(String),
    /// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
    #[error("URL scheme not supported")]
    UnsupportedUrlScheme,
    /// The URL host name, though included, is empty.
    #[error("URL contains empty host name")]
    EmptyHostName,
    /// The URL does not include a path/query.
    #[error("No path/query in URL")]
    NoPathOrQuery,
}

/// TLS errors.
///
/// Note that even if you enable only the rustls-based TLS support, the error at runtime could still
/// be `Native`, as another crate in the dependency graph may enable native TLS support.
#[allow(missing_copy_implementations)]
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TlsError {
    /// Native TLS error.
    #[cfg(feature = "native-tls")]
    #[error("native-tls error: {0}")]
    Native(#[from] native_tls_crate::Error),
    /// Rustls error.
    #[cfg(feature = "rustls-tls")]
    #[error("rustls error: {0}")]
    Rustls(#[from] rustls::TLSError),
    /// DNS name resolution error.
    #[cfg(feature = "rustls-tls")]
    #[error("Invalid DNS name: {0}")]
    Dns(#[from] webpki::InvalidDNSNameError),
}
<commit_msg>Implement From<CapacityError> and From<UrlError> for Error.<commit_after>//! Error handling.

use std::{io, result, str, string};

use crate::protocol::{frame::coding::Data, Message};
use http::Response;
use thiserror::Error;

/// Result type of all Tungstenite library calls.
pub type Result<T> = result::Result<T, Error>;

/// Possible WebSocket errors.
#[derive(Error, Debug)]
pub enum Error {
    /// WebSocket connection closed normally. This informs you of the close.
    /// It's not an error as such and nothing wrong happened.
    ///
    /// This is returned as soon as the close handshake is finished (we have both sent and
    /// received a close frame) on the server end and as soon as the server has closed the
    /// underlying connection if this endpoint is a client.
    ///
    /// Thus when you receive this, it is safe to drop the underlying connection.
    ///
    /// Receiving this error means that the WebSocket object is not usable anymore and the
    /// only meaningful action with it is dropping it.
    #[error("Connection closed normally")]
    ConnectionClosed,
    /// Trying to work with already closed connection.
    ///
    /// Trying to read or write after receiving `ConnectionClosed` causes this.
    ///
    /// As opposed to `ConnectionClosed`, this indicates your code tries to operate on the
    /// connection when it really shouldn't anymore, so this really indicates a programmer
    /// error on your part.
    #[error("Trying to work with closed connection")]
    AlreadyClosed,
    /// Input-output error. Apart from WouldBlock, these are generally errors with the
    /// underlying connection and you should probably consider them fatal.
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    /// TLS error.
    ///
    /// Note that this error variant is enabled unconditionally even if no TLS feature is enabled,
    /// to provide a feature-agnostic API surface.
    #[error("TLS error: {0}")]
    Tls(#[from] TlsError),
    /// - When reading: buffer capacity exhausted.
    /// - When writing: your message is bigger than the configured max message size
    ///   (64MB by default).
    #[error("Space limit exceeded: {0}")]
    Capacity(#[from] CapacityError),
    /// Protocol violation.
    #[error("WebSocket protocol error: {0}")]
    Protocol(#[from] ProtocolError),
    /// Message send queue full.
    #[error("Send queue is full")]
    SendQueueFull(Message),
    /// UTF coding error.
    #[error("UTF-8 encoding error")]
    Utf8,
    /// Invalid URL.
    #[error("URL error: {0}")]
    Url(#[from] UrlError),
    /// HTTP error.
    #[error("HTTP error: {}", .0.status())]
    Http(Response<Option<String>>),
    /// HTTP format error.
    #[error("HTTP format error: {0}")]
    HttpFormat(#[from] http::Error),
}

impl From<str::Utf8Error> for Error {
    fn from(_: str::Utf8Error) -> Self {
        Error::Utf8
    }
}

impl From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Self {
        Error::Utf8
    }
}

impl From<http::header::InvalidHeaderValue> for Error {
    fn from(err: http::header::InvalidHeaderValue) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::InvalidHeaderName> for Error {
    fn from(err: http::header::InvalidHeaderName) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::header::ToStrError> for Error {
    fn from(_: http::header::ToStrError) -> Self {
        Error::Utf8
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(err: http::uri::InvalidUri) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<http::status::InvalidStatusCode> for Error {
    fn from(err: http::status::InvalidStatusCode) -> Self {
        Error::HttpFormat(err.into())
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Self {
        match err {
            httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
            e => Error::Protocol(ProtocolError::HttparseError(e)),
        }
    }
}

/// Indicates the specific type/cause of a capacity error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum CapacityError {
    /// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
    #[error("Too many headers")]
    TooManyHeaders,
    /// Received header is too long.
    #[error("Header too long")]
    HeaderTooLong,
    /// Message is bigger than the maximum allowed size.
    #[error("Message too long: {size} > {max_size}")]
    MessageTooLong {
        /// The size of the message.
        size: usize,
        /// The maximum allowed message size.
        max_size: usize,
    },
    /// TCP buffer is full.
    #[error("Incoming TCP buffer is full")]
    TcpBufferFull,
}

/// Indicates the specific type/cause of a protocol error.
#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
pub enum ProtocolError {
    /// Use of the wrong HTTP method (the WebSocket protocol requires the GET method be used).
    #[error("Unsupported HTTP method used - only GET is allowed")]
    WrongHttpMethod,
    /// Wrong HTTP version used (the WebSocket protocol requires version 1.1 or higher).
    #[error("HTTP version must be 1.1 or higher")]
    WrongHttpVersion,
    /// Missing `Connection: upgrade` HTTP header.
    #[error("No \"Connection: upgrade\" header")]
    MissingConnectionUpgradeHeader,
    /// Missing `Upgrade: websocket` HTTP header.
    #[error("No \"Upgrade: websocket\" header")]
    MissingUpgradeWebSocketHeader,
    /// Missing `Sec-WebSocket-Version: 13` HTTP header.
    #[error("No \"Sec-WebSocket-Version: 13\" header")]
    MissingSecWebSocketVersionHeader,
    /// Missing `Sec-WebSocket-Key` HTTP header.
    #[error("No \"Sec-WebSocket-Key\" header")]
    MissingSecWebSocketKey,
    /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
    #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
    SecWebSocketAcceptKeyMismatch,
    /// Garbage data encountered after client request.
    #[error("Junk after client request")]
    JunkAfterRequest,
    /// Custom responses must be unsuccessful.
    #[error("Custom response must not be successful")]
    CustomResponseSuccessful,
    /// No more data while still performing handshake.
    #[error("Handshake not finished")]
    HandshakeIncomplete,
    /// Wrapper around a [`httparse::Error`] value.
    #[error("httparse error: {0}")]
    HttparseError(#[from] httparse::Error),
    /// Not allowed to send after having sent a closing frame.
    #[error("Sending after closing is not allowed")]
    SendAfterClosing,
    /// Remote sent data after sending a closing frame.
    #[error("Remote sent after having closed")]
    ReceivedAfterClosing,
    /// Reserved bits in frame header are non-zero.
    #[error("Reserved bits are non-zero")]
    NonZeroReservedBits,
    /// The server must close the connection when an unmasked frame is received.
    #[error("Received an unmasked frame from client")]
    UnmaskedFrameFromClient,
    /// The client must close the connection when a masked frame is received.
    #[error("Received a masked frame from server")]
    MaskedFrameFromServer,
    /// Control frames must not be fragmented.
    #[error("Fragmented control frame")]
    FragmentedControlFrame,
    /// Control frames must have a payload of 125 bytes or less.
    #[error("Control frame too big (payload must be 125 bytes or less)")]
    ControlFrameTooBig,
    /// Type of control frame not recognised.
    #[error("Unknown control frame type: {0}")]
    UnknownControlFrameType(u8),
    /// Type of data frame not recognised.
    #[error("Unknown data frame type: {0}")]
    UnknownDataFrameType(u8),
    /// Received a continue frame despite there being nothing to continue.
    #[error("Continue frame but nothing to continue")]
    UnexpectedContinueFrame,
    /// Received data while waiting for more fragments.
    #[error("While waiting for more fragments received: {0}")]
    ExpectedFragment(Data),
    /// Connection closed without performing the closing handshake.
    #[error("Connection reset without closing handshake")]
    ResetWithoutClosingHandshake,
    /// Encountered an invalid opcode.
    #[error("Encountered invalid opcode: {0}")]
    InvalidOpcode(u8),
    /// The payload for the closing frame is invalid.
    #[error("Invalid close sequence")]
    InvalidCloseSequence,
}

/// Indicates the specific type/cause of URL error.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum UrlError {
    /// TLS is used despite not being compiled with the TLS feature enabled.
    #[error("TLS support not compiled in")]
    TlsFeatureNotEnabled,
    /// The URL does not include a host name.
    #[error("No host name in the URL")]
    NoHostName,
    /// Failed to connect with this URL.
    #[error("Unable to connect to {0}")]
    UnableToConnect(String),
    /// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
    #[error("URL scheme not supported")]
    UnsupportedUrlScheme,
    /// The URL host name, though included, is empty.
    #[error("URL contains empty host name")]
    EmptyHostName,
    /// The URL does not include a path/query.
    #[error("No path/query in URL")]
    NoPathOrQuery,
}

/// TLS errors.
///
/// Note that even if you enable only the rustls-based TLS support, the error at runtime could still
/// be `Native`, as another crate in the dependency graph may enable native TLS support.
#[allow(missing_copy_implementations)]
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TlsError {
    /// Native TLS error.
    #[cfg(feature = "native-tls")]
    #[error("native-tls error: {0}")]
    Native(#[from] native_tls_crate::Error),
    /// Rustls error.
    #[cfg(feature = "rustls-tls")]
    #[error("rustls error: {0}")]
    Rustls(#[from] rustls::TLSError),
    /// DNS name resolution error.
    #[cfg(feature = "rustls-tls")]
    #[error("Invalid DNS name: {0}")]
    Dns(#[from] webpki::InvalidDNSNameError),
}
<|endoftext|>


<commit_before>//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::str::FromStr;
use std::result;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList
            | ErrorCode::EofWhileParsingObject
            | ErrorCode::EofWhileParsingString
            | ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon
            | ErrorCode::ExpectedListCommaOrEnd
            | ErrorCode::ExpectedObjectCommaOrEnd
            | ErrorCode::ExpectedObjectOrArray
            | ErrorCode::ExpectedSomeIdent
            | ErrorCode::ExpectedSomeValue
            | ErrorCode::ExpectedSomeString
            | ErrorCode::InvalidEscape
            | ErrorCode::InvalidNumber
            | ErrorCode::NumberOutOfRange
            | ErrorCode::InvalidUnicodeCodePoint
            | ErrorCode::ControlCharacterWhileParsingString
            | ErrorCode::KeyMustBeAString
            | ErrorCode::LoneLeadingSurrogateInHexEscape
            | ErrorCode::TrailingComma
            | ErrorCode::TrailingCharacters
            | ErrorCode::UnexpectedEndOfHexEscape
            | ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```edition2018
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(Box<str>),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Control character found while parsing a string.
    ControlCharacterWhileParsingString,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has a comma after the last value in an array or map.
    TrailingComma,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    #[cold]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(ErrorImpl {
                code: code,
                line: line,
                column: column,
            }),
        }
    }

    // Not public API. Should be pub(crate).
    //
    // Update `eager_json` crate when this function changes.
    #[doc(hidden)]
    #[cold]
    pub fn io(error: io::Error) -> Self {
        Error {
            err: Box::new(ErrorImpl {
                code: ErrorCode::Io(error),
                line: 0,
                column: 0,
            }),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    #[cold]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::ControlCharacterWhileParsingString => {
                f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
            }
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingComma => f.write_str("trailing comma"),
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.err.code {
            ErrorCode::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&*self.err, f)
    }
}

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code, self.line, self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Error({:?}, line: {}, column: {})",
            self.err.code.to_string(),
            self.err.line,
            self.err.column
        )
    }
}

impl de::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }

    #[cold]
    fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
        if let de::Unexpected::Unit = unexp {
            Error::custom(format_args!("invalid type: null, expected {}", exp))
        } else {
            Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
        }
    }
}

impl ser::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }
}

// Parse our own error message that looks like "{} at line {} column {}" to work
// around erased-serde round-tripping the error through de::Error::custom.
fn make_error(mut msg: String) -> Error {
    let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0));
    Error {
        err: Box::new(ErrorImpl {
            code: ErrorCode::Message(msg.into_boxed_str()),
            line: line,
            column: column,
        }),
    }
}

fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> {
    let start_of_suffix = match msg.rfind(" at line ") {
        Some(index) => index,
        None => return None,
    };

    // Find start and end of line number.
    let start_of_line = start_of_suffix + " at line ".len();
    let mut end_of_line = start_of_line;
    while starts_with_digit(&msg[end_of_line..]) {
        end_of_line += 1;
    }

    if !msg[end_of_line..].starts_with(" column ") {
        return None;
    }

    // Find start and end of column number.
    let start_of_column = end_of_line + " column ".len();
    let mut end_of_column = start_of_column;
    while starts_with_digit(&msg[end_of_column..]) {
        end_of_column += 1;
    }

    if end_of_column < msg.len() {
        return None;
    }

    // Parse numbers.
    let line = match usize::from_str(&msg[start_of_line..end_of_line]) {
        Ok(line) => line,
        Err(_) => return None,
    };
    let column = match usize::from_str(&msg[start_of_column..end_of_column]) {
        Ok(column) => column,
        Err(_) => return None,
    };

    msg.truncate(start_of_suffix);
    Some((line, column))
}

fn starts_with_digit(slice: &str) -> bool {
    match slice.as_bytes().get(0) {
        None => false,
        Some(&byte) => byte >= b'0' && byte <= b'9',
    }
}
<commit_msg>Format with rustfmt 2019-02-14<commit_after>//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use std::str::FromStr;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList
            | ErrorCode::EofWhileParsingObject
            | ErrorCode::EofWhileParsingString
            | ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon
            | ErrorCode::ExpectedListCommaOrEnd
            | ErrorCode::ExpectedObjectCommaOrEnd
            | ErrorCode::ExpectedObjectOrArray
            | ErrorCode::ExpectedSomeIdent
            | ErrorCode::ExpectedSomeValue
            | ErrorCode::ExpectedSomeString
            | ErrorCode::InvalidEscape
            | ErrorCode::InvalidNumber
            | ErrorCode::NumberOutOfRange
            | ErrorCode::InvalidUnicodeCodePoint
            | ErrorCode::ControlCharacterWhileParsingString
            | ErrorCode::KeyMustBeAString
            | ErrorCode::LoneLeadingSurrogateInHexEscape
            | ErrorCode::TrailingComma
            | ErrorCode::TrailingCharacters
            | ErrorCode::UnexpectedEndOfHexEscape
            | ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```edition2018
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(Box<str>),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Control character found while parsing a string.
    ControlCharacterWhileParsingString,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has a comma after the last value in an array or map.
    TrailingComma,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    #[cold]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(ErrorImpl {
                code: code,
                line: line,
                column: column,
            }),
        }
    }

    // Not public API. Should be pub(crate).
    //
    // Update `eager_json` crate when this function changes.
    #[doc(hidden)]
    #[cold]
    pub fn io(error: io::Error) -> Self {
        Error {
            err: Box::new(ErrorImpl {
                code: ErrorCode::Io(error),
                line: 0,
                column: 0,
            }),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    #[cold]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::ControlCharacterWhileParsingString => {
                f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
            }
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingComma => f.write_str("trailing comma"),
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.err.code {
            ErrorCode::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&*self.err, f)
    }
}

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code, self.line, self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Error({:?}, line: {}, column: {})",
            self.err.code.to_string(),
            self.err.line,
            self.err.column
        )
    }
}

impl de::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }

    #[cold]
    fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
        if let de::Unexpected::Unit = unexp {
            Error::custom(format_args!("invalid type: null, expected {}", exp))
        } else {
            Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
        }
    }
}

impl ser::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }
}

// Parse our own error message that looks like "{} at line {} column {}" to work
// around erased-serde round-tripping the error through de::Error::custom.
fn make_error(mut msg: String) -> Error {
    let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0));
    Error {
        err: Box::new(ErrorImpl {
            code: ErrorCode::Message(msg.into_boxed_str()),
            line: line,
            column: column,
        }),
    }
}

fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> {
    let start_of_suffix = match msg.rfind(" at line ") {
        Some(index) => index,
        None => return None,
    };

    // Find start and end of line number.
    let start_of_line = start_of_suffix + " at line ".len();
    let mut end_of_line = start_of_line;
    while starts_with_digit(&msg[end_of_line..]) {
        end_of_line += 1;
    }

    if !msg[end_of_line..].starts_with(" column ") {
        return None;
    }

    // Find start and end of column number.
    let start_of_column = end_of_line + " column ".len();
    let mut end_of_column = start_of_column;
    while starts_with_digit(&msg[end_of_column..]) {
        end_of_column += 1;
    }

    if end_of_column < msg.len() {
        return None;
    }

    // Parse numbers.
    let line = match usize::from_str(&msg[start_of_line..end_of_line]) {
        Ok(line) => line,
        Err(_) => return None,
    };
    let column = match usize::from_str(&msg[start_of_column..end_of_column]) {
        Ok(column) => column,
        Err(_) => return None,
    };

    msg.truncate(start_of_suffix);
    Some((line, column))
}

fn starts_with_digit(slice: &str) -> bool {
    match slice.as_bytes().get(0) {
        None => false,
        Some(&byte) => byte >= b'0' && byte <= b'9',
    }
}
<|endoftext|>


<commit_before>use libc::c_uint;

use ffi::*;

bitflags! {
    #[doc="Environment Options"]
    pub flags EnvironmentFlags: c_uint {

        #[doc="Use a fixed address for the mmap region. This flag must be specified"]
        #[doc="when creating the environment, and is stored persistently in the environment."]
        #[doc="If successful, the memory map will always reside at the same virtual address"]
        #[doc="and pointers used to reference data items in the database will be constant"]
        #[doc="across multiple invocations. This option may not always work, depending on"]
        #[doc="how the operating system has allocated memory to shared libraries and other uses."]
        #[doc="The feature is highly experimental."]
        const FIXED_MAP = MDB_FIXEDMAP,

        #[doc="By default, LMDB creates its environment in a directory whose pathname is given in"]
        #[doc="`path`, and creates its data and lock files under that directory. With this option,"]
        #[doc="`path` is used as-is for the database main data file. The database lock file is the"]
        #[doc="`path` with `-lock` appended."]
        const NO_SUB_DIR = MDB_NOSUBDIR,

        #[doc="Use a writeable memory map unless `READ_ONLY` is set. This is faster and uses"]
        #[doc="fewer mallocs, but loses protection from application bugs like wild pointer writes"]
        #[doc="and other bad updates into the database. Incompatible with nested transactions."]
        #[doc="Processes with and without `WRITE_MAP` on the same environment do not cooperate"]
        #[doc="well."]
        const WRITE_MAP = MDB_WRITEMAP,

        #[doc="Open the environment in read-only mode. No write operations will be allowed."]
        #[doc="When opening an environment, LMDB will still modify the lock file - except on"]
        #[doc="read-only filesystems, where LMDB does not use locks."]
        const READ_ONLY = MDB_RDONLY,

        #[doc="Flush system buffers to disk only once per transaction, omit the metadata flush."]
        #[doc="Defer that until the system flushes files to disk, or next non-`READ_ONLY` commit"]
        #[doc="or `Environment::sync`. This optimization maintains database integrity, but a"]
        #[doc="system crash may undo the last committed transaction. I.e. it preserves the ACI"]
        #[doc="(atomicity, consistency, isolation) but not D (durability) database property."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_META_SYNC = MDB_NOMETASYNC,

        #[doc="Don't flush system buffers to disk when committing a transaction. This optimization"]
        #[doc="means a system crash can corrupt the database or lose the last transactions if"]
        #[doc="buffers are not yet flushed to disk. The risk is governed by how often the system"]
        #[doc="flushes dirty buffers to disk and how often `Environment::sync` is called. However,"]
        #[doc="if the filesystem preserves write order and the `WRITE_MAP` flag is not used,"]
        #[doc="transactions exhibit ACI (atomicity, consistency, isolation) properties and only"]
        #[doc="lose D (durability). I.e. database integrity is maintained, but a system"]
        #[doc="crash may undo the final transactions. Note that (`NO_SYNC | WRITE_MAP`) leaves the"]
        #[doc="system with no hint for when to write transactions to disk, unless"]
        #[doc="`Environment::sync` is called. (`MAP_ASYNC | WRITE_MAP`) may be preferable."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_SYNC = MDB_NOSYNC,

        #[doc="When using `WRITE_MAP`, use asynchronous flushes to disk. As with `NO_SYNC`, a"]
        #[doc="system crash can then corrupt the database or lose the last transactions. Calling"]
        #[doc="`Environment::sync` ensures on-disk database integrity until next commit."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const MAP_ASYNC = MDB_MAPASYNC,

        #[doc="Don't use thread-local storage. Tie reader locktable slots to transaction objects"]
        #[doc="instead of to threads. I.e. `RoTransaction::reset` keeps the slot reseved for the"]
        #[doc="transaction object. A thread may use parallel read-only transactions. A read-only"]
        #[doc="transaction may span threads if the user synchronizes its use. Applications that"]
        #[doc="multiplex many the user synchronizes its use. Applications that multiplex many user"]
        #[doc="threads over individual OS threads need this option. Such an application must also"]
        #[doc="serialize the write transactions in an OS thread, since LMDB's write locking is"]
        #[doc="unaware of the user threads."]
        const NO_TLS = MDB_NOTLS,

        #[doc="Do not do any locking. If concurrent access is anticipated, the caller must manage"]
        #[doc="all concurrency themself. For proper operation the caller must enforce"]
        #[doc="single-writer semantics, and must ensure that no readers are using old"]
        #[doc="transactions while a writer is active. The simplest approach is to use an exclusive"]
        #[doc="lock so that no readers may be active at all when a writer begins."]
        const NO_LOCK = MDB_NOLOCK,

        #[doc="Turn off readahead. Most operating systems perform readahead on read requests by"]
        #[doc="default. This option turns it off if the OS supports it. Turning it off may help"]
        #[doc="random read performance when the DB is larger than RAM and system RAM is full."]
        #[doc="The option is not implemented on Windows."]
        const NO_READAHEAD = MDB_NORDAHEAD,

        #[doc="Do not initialize malloc'd memory before writing to unused spaces in the data file."]
        #[doc="By default, memory for pages written to the data file is obtained using malloc."]
        #[doc="While these pages may be reused in subsequent transactions, freshly malloc'd pages"]
        #[doc="will be initialized to zeroes before use. This avoids persisting leftover data from"]
        #[doc="other code (that used the heap and subsequently freed the memory) into the data"]
        #[doc="file. Note that many other system libraries may allocate and free memory from the"]
        #[doc="heap for arbitrary uses. E.g., stdio may use the heap for file I/O buffers. This"]
        #[doc="initialization step has a modest performance cost so some applications may want to"]
        #[doc="disable it using this flag. This option can be a problem for applications which"]
        #[doc="handle sensitive data like passwords, and it makes memory checkers like Valgrind"]
        #[doc="noisy. This flag is not needed with `WRITE_MAP`, which writes directly to the mmap"]
        #[doc="instead of using malloc for pages. The initialization is also skipped if writing"]
        #[doc="with reserve; the caller is expected to overwrite all of the memory that was"]
        #[doc="reserved in that case."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_MEM_INIT = MDB_NOMEMINIT,
    }
}

bitflags! {
    #[doc="Database Options"]
    pub flags DatabaseFlags: c_uint {

        #[doc="Keys are strings to be compared in reverse order, from the end of the strings"]
        #[doc="to the beginning. By default, Keys are treated as strings and compared from"]
        #[doc="beginning to end."]
        const REVERSE_KEY = MDB_REVERSEKEY,

        #[doc="Duplicate keys may be used in the database. (Or, from another perspective,"]
        #[doc="keys may have multiple data items, stored in sorted order.) By default"]
        #[doc="keys must be unique and may have only a single data item."]
        const DUP_SORT = MDB_DUPSORT,

        #[doc="Keys are binary integers in native byte order. Setting this option requires all"]
        #[doc="keys to be the same size, typically 32 or 64 bits."]
        const INTEGER_KEY = MDB_INTEGERKEY,

        #[doc="This flag may only be used in combination with `DUP_SORT`. This option tells"]
        #[doc="the library that the data items for this database are all the same size, which"]
        #[doc="allows further optimizations in storage and retrieval. When all data items are"]
        #[doc="the same size, the `GET_MULTIPLE` and `NEXT_MULTIPLE` cursor operations may be"]
        #[doc="used to retrieve multiple items at once."]
        const DUP_FIXED = MDB_DUPFIXED,

        #[doc="This option specifies that duplicate data items are also integers, and"]
        #[doc="should be sorted as such."]
        const INTEGER_DUP = MDB_INTEGERDUP,

        #[doc="This option specifies that duplicate data items should be compared as strings"]
        #[doc="in reverse order."]
        const REVERSE_DUP = MDB_REVERSEDUP,
    }
}

bitflags! {
    #[doc="Write Options"]
    pub flags WriteFlags: c_uint {

        #[doc="Insert the new item only if the key does not already appear in the database."]
        #[doc="The function will return `LmdbError::KeyExist` if the key already appears in the"]
        #[doc="database, even if the database supports duplicates (`DUP_SORT`)."]
        const NO_OVERWRITE = MDB_NOOVERWRITE,

        #[doc="Insert the new item only if it does not already appear in the database."]
        #[doc="This flag may only be specified if the database was opened with `DUP_SORT`."]
        #[doc="The function will return `LmdbError::KeyExist` if the item already appears in the"]
        #[doc="database."]
        const NO_DUP_DATA = MDB_NODUPDATA,

        #[doc="For `Cursor::put`. Replace the item at the current cursor position. The key"]
        #[doc="parameter must match the current position. If using sorted duplicates (`DUP_SORT`)"]
        #[doc="the data item must still sort into the same position. This is intended to be used"]
        #[doc="when the new data is the same size as the old. Otherwise it will simply perform a"]
        #[doc="delete of the old record followed by an insert."]
        const CURRENT = MDB_CURRENT,

        #[doc="Append the given item to the end of the database. No key comparisons are performed."]
        #[doc="This option allows fast bulk loading when keys are already known to be in the"]
        #[doc="correct order. Loading unsorted keys with this flag will cause data corruption."]
        const APPEND = MDB_APPEND,

        #[doc="Same as `APPEND`, but for sorted dup data."]
        const APPEND_DUP = MDB_APPENDDUP,
    }
}
<commit_msg>Fix typo. (#10)<commit_after>use libc::c_uint;

use ffi::*;

bitflags! {
    #[doc="Environment Options"]
    pub flags EnvironmentFlags: c_uint {

        #[doc="Use a fixed address for the mmap region. This flag must be specified"]
        #[doc="when creating the environment, and is stored persistently in the environment."]
        #[doc="If successful, the memory map will always reside at the same virtual address"]
        #[doc="and pointers used to reference data items in the database will be constant"]
        #[doc="across multiple invocations. This option may not always work, depending on"]
        #[doc="how the operating system has allocated memory to shared libraries and other uses."]
        #[doc="The feature is highly experimental."]
        const FIXED_MAP = MDB_FIXEDMAP,

        #[doc="By default, LMDB creates its environment in a directory whose pathname is given in"]
        #[doc="`path`, and creates its data and lock files under that directory. With this option,"]
        #[doc="`path` is used as-is for the database main data file. The database lock file is the"]
        #[doc="`path` with `-lock` appended."]
        const NO_SUB_DIR = MDB_NOSUBDIR,

        #[doc="Use a writeable memory map unless `READ_ONLY` is set. This is faster and uses"]
        #[doc="fewer mallocs, but loses protection from application bugs like wild pointer writes"]
        #[doc="and other bad updates into the database. Incompatible with nested transactions."]
        #[doc="Processes with and without `WRITE_MAP` on the same environment do not cooperate"]
        #[doc="well."]
        const WRITE_MAP = MDB_WRITEMAP,

        #[doc="Open the environment in read-only mode. No write operations will be allowed."]
        #[doc="When opening an environment, LMDB will still modify the lock file - except on"]
        #[doc="read-only filesystems, where LMDB does not use locks."]
        const READ_ONLY = MDB_RDONLY,

        #[doc="Flush system buffers to disk only once per transaction, omit the metadata flush."]
        #[doc="Defer that until the system flushes files to disk, or next non-`READ_ONLY` commit"]
        #[doc="or `Environment::sync`. This optimization maintains database integrity, but a"]
        #[doc="system crash may undo the last committed transaction. I.e. it preserves the ACI"]
        #[doc="(atomicity, consistency, isolation) but not D (durability) database property."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_META_SYNC = MDB_NOMETASYNC,

        #[doc="Don't flush system buffers to disk when committing a transaction. This optimization"]
        #[doc="means a system crash can corrupt the database or lose the last transactions if"]
        #[doc="buffers are not yet flushed to disk. The risk is governed by how often the system"]
        #[doc="flushes dirty buffers to disk and how often `Environment::sync` is called. However,"]
        #[doc="if the filesystem preserves write order and the `WRITE_MAP` flag is not used,"]
        #[doc="transactions exhibit ACI (atomicity, consistency, isolation) properties and only"]
        #[doc="lose D (durability). I.e. database integrity is maintained, but a system"]
        #[doc="crash may undo the final transactions. Note that (`NO_SYNC | WRITE_MAP`) leaves the"]
        #[doc="system with no hint for when to write transactions to disk, unless"]
        #[doc="`Environment::sync` is called. (`MAP_ASYNC | WRITE_MAP`) may be preferable."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_SYNC = MDB_NOSYNC,

        #[doc="When using `WRITE_MAP`, use asynchronous flushes to disk. As with `NO_SYNC`, a"]
        #[doc="system crash can then corrupt the database or lose the last transactions. Calling"]
        #[doc="`Environment::sync` ensures on-disk database integrity until next commit."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const MAP_ASYNC = MDB_MAPASYNC,

        #[doc="Don't use thread-local storage. Tie reader locktable slots to transaction objects"]
        #[doc="instead of to threads. I.e. `RoTransaction::reset` keeps the slot reserved for the"]
        #[doc="transaction object. A thread may use parallel read-only transactions. A read-only"]
        #[doc="transaction may span threads if the user synchronizes its use. Applications that"]
        #[doc="multiplex many the user synchronizes its use. Applications that multiplex many user"]
        #[doc="threads over individual OS threads need this option. Such an application must also"]
        #[doc="serialize the write transactions in an OS thread, since LMDB's write locking is"]
        #[doc="unaware of the user threads."]
        const NO_TLS = MDB_NOTLS,

        #[doc="Do not do any locking. If concurrent access is anticipated, the caller must manage"]
        #[doc="all concurrency themself. For proper operation the caller must enforce"]
        #[doc="single-writer semantics, and must ensure that no readers are using old"]
        #[doc="transactions while a writer is active. The simplest approach is to use an exclusive"]
        #[doc="lock so that no readers may be active at all when a writer begins."]
        const NO_LOCK = MDB_NOLOCK,

        #[doc="Turn off readahead. Most operating systems perform readahead on read requests by"]
        #[doc="default. This option turns it off if the OS supports it. Turning it off may help"]
        #[doc="random read performance when the DB is larger than RAM and system RAM is full."]
        #[doc="The option is not implemented on Windows."]
        const NO_READAHEAD = MDB_NORDAHEAD,

        #[doc="Do not initialize malloc'd memory before writing to unused spaces in the data file."]
        #[doc="By default, memory for pages written to the data file is obtained using malloc."]
        #[doc="While these pages may be reused in subsequent transactions, freshly malloc'd pages"]
        #[doc="will be initialized to zeroes before use. This avoids persisting leftover data from"]
        #[doc="other code (that used the heap and subsequently freed the memory) into the data"]
        #[doc="file. Note that many other system libraries may allocate and free memory from the"]
        #[doc="heap for arbitrary uses. E.g., stdio may use the heap for file I/O buffers. This"]
        #[doc="initialization step has a modest performance cost so some applications may want to"]
        #[doc="disable it using this flag. This option can be a problem for applications which"]
        #[doc="handle sensitive data like passwords, and it makes memory checkers like Valgrind"]
        #[doc="noisy. This flag is not needed with `WRITE_MAP`, which writes directly to the mmap"]
        #[doc="instead of using malloc for pages. The initialization is also skipped if writing"]
        #[doc="with reserve; the caller is expected to overwrite all of the memory that was"]
        #[doc="reserved in that case."]
        #[doc="\n\nThis flag may be changed at any time using `Environment::set_flags`."]
        const NO_MEM_INIT = MDB_NOMEMINIT,
    }
}

bitflags! {
    #[doc="Database Options"]
    pub flags DatabaseFlags: c_uint {

        #[doc="Keys are strings to be compared in reverse order, from the end of the strings"]
        #[doc="to the beginning. By default, Keys are treated as strings and compared from"]
        #[doc="beginning to end."]
        const REVERSE_KEY = MDB_REVERSEKEY,

        #[doc="Duplicate keys may be used in the database. (Or, from another perspective,"]
        #[doc="keys may have multiple data items, stored in sorted order.) By default"]
        #[doc="keys must be unique and may have only a single data item."]
        const DUP_SORT = MDB_DUPSORT,

        #[doc="Keys are binary integers in native byte order. Setting this option requires all"]
        #[doc="keys to be the same size, typically 32 or 64 bits."]
        const INTEGER_KEY = MDB_INTEGERKEY,

        #[doc="This flag may only be used in combination with `DUP_SORT`. This option tells"]
        #[doc="the library that the data items for this database are all the same size, which"]
        #[doc="allows further optimizations in storage and retrieval. When all data items are"]
        #[doc="the same size, the `GET_MULTIPLE` and `NEXT_MULTIPLE` cursor operations may be"]
        #[doc="used to retrieve multiple items at once."]
        const DUP_FIXED = MDB_DUPFIXED,

        #[doc="This option specifies that duplicate data items are also integers, and"]
        #[doc="should be sorted as such."]
        const INTEGER_DUP = MDB_INTEGERDUP,

        #[doc="This option specifies that duplicate data items should be compared as strings"]
        #[doc="in reverse order."]
        const REVERSE_DUP = MDB_REVERSEDUP,
    }
}

bitflags! {
    #[doc="Write Options"]
    pub flags WriteFlags: c_uint {

        #[doc="Insert the new item only if the key does not already appear in the database."]
        #[doc="The function will return `LmdbError::KeyExist` if the key already appears in the"]
        #[doc="database, even if the database supports duplicates (`DUP_SORT`)."]
        const NO_OVERWRITE = MDB_NOOVERWRITE,

        #[doc="Insert the new item only if it does not already appear in the database."]
        #[doc="This flag may only be specified if the database was opened with `DUP_SORT`."]
        #[doc="The function will return `LmdbError::KeyExist` if the item already appears in the"]
        #[doc="database."]
        const NO_DUP_DATA = MDB_NODUPDATA,

        #[doc="For `Cursor::put`. Replace the item at the current cursor position. The key"]
        #[doc="parameter must match the current position. If using sorted duplicates (`DUP_SORT`)"]
        #[doc="the data item must still sort into the same position. This is intended to be used"]
        #[doc="when the new data is the same size as the old. Otherwise it will simply perform a"]
        #[doc="delete of the old record followed by an insert."]
        const CURRENT = MDB_CURRENT,

        #[doc="Append the given item to the end of the database. No key comparisons are performed."]
        #[doc="This option allows fast bulk loading when keys are already known to be in the"]
        #[doc="correct order. Loading unsorted keys with this flag will cause data corruption."]
        const APPEND = MDB_APPEND,

        #[doc="Same as `APPEND`, but for sorted dup data."]
        const APPEND_DUP = MDB_APPENDDUP,
    }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.5, 1.0, 0.2, 0.5, 0.5, 0.5, 0.5, 0.5];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_NORMAL: f64 = 0.5;
pub const SIGNAL_FLUID_DECAY: f64 = 0.00001;

const TIMESTEP: f64 = 0.5;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[0];
        let kill = self.fluids[2];
        let f = 0.029;
        let k = 0.057;
        [a * b * b - (k + f) * b,
         -a * b * b + f * (1.0 - a),
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[3]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[4]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[5]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[6]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[7])]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<commit_msg>increase decay of signals<commit_after>extern crate num;
extern crate nalgebra as na;

pub const TOTAL_FLUIDS: usize = 8;
pub const NORMAL_DIFFUSION: [f64; TOTAL_FLUIDS] = [0.5, 1.0, 0.2, 0.5, 0.5, 0.5, 0.5, 0.5];
pub const KILL_FLUID_NORMAL: f64 = 0.05;
pub const KILL_FLUID_DECAY: f64 = 0.01;
pub const KILL_FLUID_UPPER_THRESHOLD: f64 = 0.052;
pub const KILL_FLUID_LOWER_THRESHOLD: f64 = 0.048;
pub const SIGNAL_FLUID_NORMAL: f64 = 0.5;
pub const SIGNAL_FLUID_DECAY: f64 = 0.001;

const TIMESTEP: f64 = 0.5;

#[derive(Default, Debug)]
pub struct Solution {
    pub fluids: [f64; TOTAL_FLUIDS],
    pub coefficients: [f64; TOTAL_FLUIDS],
    pub diffuse: [f64; TOTAL_FLUIDS],
}

impl Solution {
    pub fn new(fluids: [f64; TOTAL_FLUIDS], coefficients: [f64; TOTAL_FLUIDS]) -> Self {
        Solution {
            fluids: fluids,
            coefficients: coefficients,
            diffuse: [0.0; TOTAL_FLUIDS],
        }
    }

    pub fn react_deltas(&self) -> [f64; TOTAL_FLUIDS] {
        let a = self.fluids[1];
        let b = self.fluids[0];
        let kill = self.fluids[2];
        let f = 0.029;
        let k = 0.057;
        [a * b * b - (k + f) * b,
         -a * b * b + f * (1.0 - a),
         KILL_FLUID_DECAY * (KILL_FLUID_NORMAL - kill),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[3]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[4]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[5]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[6]),
         SIGNAL_FLUID_DECAY * (SIGNAL_FLUID_NORMAL - self.fluids[7])]
    }

    pub fn diffuse_from(&mut self, other: &Solution) {
        for i in 0..TOTAL_FLUIDS {
            self.diffuse[i] += other.fluids[i] * other.coefficients[i] / 6.0;
        }
    }

    pub fn end_cycle(&mut self) {
        let reacts = self.react_deltas();
        for i in 0..TOTAL_FLUIDS {
            self.fluids[i] += TIMESTEP *
                              (reacts[i] + self.diffuse[i] - self.coefficients[i] * self.fluids[i]);
            self.diffuse[i] = 0.0;
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello World!");
}
<commit_msg>Remove hello.rs<commit_after><|endoftext|>


<commit_before>use fragment::matching;
use ExclusionPattern;
use walkdir::{DirEntry, Error, WalkDir};
use std::path::{Path, PathBuf};
use indexed_path::IndexedPath;

pub struct Index {
    path: PathBuf,
    entries: Vec<IndexedPath>,
}

impl Index {
    pub fn new(path: PathBuf) -> Index {
        Index {
            path: path,
            entries: Vec::new()
        }
    }

    /// Finds all files inside and beneath the index path
    /// and adds them to the index entries vector.
    pub fn populate(&mut self, exclusions: Option<Vec<ExclusionPattern>>, case_sensitive: bool) {
        // The entries listed by read_dir include the root index path; we want
        // relative paths, so we get this length so that we can strip it.
        let prefix_length = match self.path.to_str() {
            Some(path) => path.len() + 1,
            None => return,
        };

        // Start indexing at the specified path.
        let filtered_entries = WalkDir::new(&self.path).into_iter().filter_entry(|entry| {
            if let Some(ref exclusions) = exclusions {
                !exclusions.iter().any(|exclusion| {
                    exclusion.matches(entry.path().to_string_lossy().as_ref())
                })
            } else {
                true
            }
        });

        for entry in filtered_entries {
            relative_entry_path(entry, prefix_length).map(|entry_path| {
                self.entries.push(
                    IndexedPath::new(entry_path, case_sensitive)
                );
            });
        }
    }

    pub fn find(&self, term: &str, limit: usize) -> Vec<&Path> {
        matching::find(term, &self.entries, limit)
            .into_iter()
            .map(|result| result.as_path())
            .collect()
    }
}

/// Transforms a DirEntry object into an optional relative path string,
/// returning None if any errors occur or if the entry is not a file.
fn relative_entry_path(entry: Result<DirEntry, Error>, prefix_length: usize) -> Option<String> {
    entry.ok().and_then(|e| {
        // Limit path look-ups to files.
        e.path().metadata().ok().and_then(|metadata| {
            if metadata.is_file() {
                // Map the absolute path to a relative one.
                e.path().to_str().map(|path| path[prefix_length..].to_string())
            } else {
                None
            }
        })
    })
}

#[cfg(test)]
mod tests {
    use super::{Index, IndexedPath, ExclusionPattern};
    use std::path::{Path, PathBuf};

    #[test]
    fn populate_respects_exclusions() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("root_file", true)];
        index.populate(Some(vec![ExclusionPattern::new("**/directory").unwrap()]), true);

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn populate_lowercases_entries_when_case_sensitive_is_false() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("directory/Capitalized_file", false),
                                    IndexedPath::new("directory/nested_file", false),
                                    IndexedPath::new("root_file", false)];
        index.populate(None, false);
        index.entries.sort();

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn populate_lowercases_entries_when_case_sensitive_is_true() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("directory/Capitalized_file", true),
                                    IndexedPath::new("directory/nested_file", true),
                                    IndexedPath::new("root_file", true)];
        index.populate(None, true);
        index.entries.sort();

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn find_defers_to_matching_module() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        index.populate(None, true);
        let term = "root";
        let limit = 5;
        let results = index.find(term, limit);

        assert_eq!(results, vec![Path::new("root_file")]);
    }
}
<commit_msg>Add Debug and PartialEq implementations to Index type<commit_after>use fragment::matching;
use ExclusionPattern;
use walkdir::{DirEntry, Error, WalkDir};
use std::path::{Path, PathBuf};
use indexed_path::IndexedPath;

#[derive(Debug, PartialEq)]
pub struct Index {
    path: PathBuf,
    entries: Vec<IndexedPath>,
}

impl Index {
    pub fn new(path: PathBuf) -> Index {
        Index {
            path: path,
            entries: Vec::new()
        }
    }

    /// Finds all files inside and beneath the index path
    /// and adds them to the index entries vector.
    pub fn populate(&mut self, exclusions: Option<Vec<ExclusionPattern>>, case_sensitive: bool) {
        // The entries listed by read_dir include the root index path; we want
        // relative paths, so we get this length so that we can strip it.
        let prefix_length = match self.path.to_str() {
            Some(path) => path.len() + 1,
            None => return,
        };

        // Start indexing at the specified path.
        let filtered_entries = WalkDir::new(&self.path).into_iter().filter_entry(|entry| {
            if let Some(ref exclusions) = exclusions {
                !exclusions.iter().any(|exclusion| {
                    exclusion.matches(entry.path().to_string_lossy().as_ref())
                })
            } else {
                true
            }
        });

        for entry in filtered_entries {
            relative_entry_path(entry, prefix_length).map(|entry_path| {
                self.entries.push(
                    IndexedPath::new(entry_path, case_sensitive)
                );
            });
        }
    }

    pub fn find(&self, term: &str, limit: usize) -> Vec<&Path> {
        matching::find(term, &self.entries, limit)
            .into_iter()
            .map(|result| result.as_path())
            .collect()
    }
}

/// Transforms a DirEntry object into an optional relative path string,
/// returning None if any errors occur or if the entry is not a file.
fn relative_entry_path(entry: Result<DirEntry, Error>, prefix_length: usize) -> Option<String> {
    entry.ok().and_then(|e| {
        // Limit path look-ups to files.
        e.path().metadata().ok().and_then(|metadata| {
            if metadata.is_file() {
                // Map the absolute path to a relative one.
                e.path().to_str().map(|path| path[prefix_length..].to_string())
            } else {
                None
            }
        })
    })
}

#[cfg(test)]
mod tests {
    use super::{Index, IndexedPath, ExclusionPattern};
    use std::path::{Path, PathBuf};

    #[test]
    fn populate_respects_exclusions() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("root_file", true)];
        index.populate(Some(vec![ExclusionPattern::new("**/directory").unwrap()]), true);

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn populate_lowercases_entries_when_case_sensitive_is_false() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("directory/Capitalized_file", false),
                                    IndexedPath::new("directory/nested_file", false),
                                    IndexedPath::new("root_file", false)];
        index.populate(None, false);
        index.entries.sort();

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn populate_lowercases_entries_when_case_sensitive_is_true() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        let expected_entries = vec![IndexedPath::new("directory/Capitalized_file", true),
                                    IndexedPath::new("directory/nested_file", true),
                                    IndexedPath::new("root_file", true)];
        index.populate(None, true);
        index.entries.sort();

        assert_eq!(index.entries, expected_entries);
    }

    #[test]
    fn find_defers_to_matching_module() {
        let path = PathBuf::from("tests/sample");
        let mut index = Index::new(path);
        index.populate(None, true);
        let term = "root";
        let limit = 5;
        let results = index.find(term, limit);

        assert_eq!(results, vec![Path::new("root_file")]);
    }
}
<|endoftext|>


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

use IntoRawMode;

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Invalid character code.
    Invalid,
    /// Null byte.
    Null,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// An iterator over input keys.
#[cfg(feature = "nightly")]
pub struct Keys<I> {
    chars: I,
}

#[cfg(feature = "nightly")]
impl<I: Iterator<Item = Result<char, io::CharsError>>> Iterator for Keys<I> {
    type Item = Result<Key, io::CharsError>;

    fn next(&mut self) -> Option<Result<Key, io::CharsError>> {
        Some(match self.chars.next() {
            Some(Ok('\x1B')) => Ok(match self.chars.next() {
                Some(Ok('O')) => match self.chars.next() {
                    Some(Ok('P')) => Key::F(1),
                    Some(Ok('Q')) => Key::F(2),
                    Some(Ok('R')) => Key::F(3),
                    Some(Ok('S')) => Key::F(4),
                    _ => Key::Invalid,
                },
                Some(Ok('[')) => match self.chars.next() {
                    Some(Ok('D')) => Key::Left,
                    Some(Ok('C')) => Key::Right,
                    Some(Ok('A')) => Key::Up,
                    Some(Ok('B')) => Key::Down,
                    Some(Ok('H')) => Key::Home,
                    Some(Ok('F')) => Key::End,
                    Some(Ok(c @ '1' ... '6')) => match self.chars.next() {
                        Some(Ok('~')) => match c {
                            '1' | '7' => Key::Home,
                            '2' | '8' => Key::Insert,
                            '3' => Key::Delete,
                            '4' => Key::End,
                            '5' => Key::PageUp,
                            '6' => Key::PageDown,
                            _ => Key::Invalid,
                        },
                        Some(Ok(k @ '0' ... '9')) => match self.chars.next() {
                            Some(Ok('~')) => match 10 * (c as u8 - b'0') + (k as u8 - b'0') {
                                v @ 11 ... 15 => Key::F(v - 10),
                                v @ 17 ... 21 => Key::F(v - 11),
                                v @ 23 ... 24 => Key::F(v - 12),
                                _ => Key::Invalid,
                            },
                            _ => Key::Invalid,
                        },
                        _ => Key::Invalid,
                    },
                    _ => Key::Invalid,
                },
                Some(Ok(c)) => Key::Alt(c),
                Some(Err(_)) | None => Key::Invalid,
            }),
            Some(Ok('\n')) | Some(Ok('\r')) => Ok(Key::Char('\n')),
            Some(Ok('\t')) => Ok(Key::Char('\t')),
            Some(Ok('\x7F')) => Ok(Key::Backspace),
            Some(Ok(c @ '\x01' ... '\x1A')) => Ok(Key::Ctrl((c as u8 - 0x1  + b'a') as char)),
            Some(Ok(c @ '\x1C' ... '\x1F')) => Ok(Key::Ctrl((c as u8 - 0x1C + b'4') as char)),
            Some(Ok('\0')) => Ok(Key::Null),
            Some(Ok(c)) => Ok(Key::Char(c)),
            Some(Err(e)) => Err(e),
            None => return None,
        })
    }
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over key inputs.
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<io::Chars<Self>> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read> TermRead for R {
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<io::Chars<R>> {
        Keys {
            chars: self.chars(),
        }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => { buf.pop(); },
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

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

    #[cfg(feature = "nightly")]
    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next().unwrap().unwrap(), Key::Alt('a'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('y'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('o'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Backspace);
        assert_eq!(i.next().unwrap().unwrap(), Key::Left);
        assert!(i.next().is_none());
    }

    fn line_match(a: &str, b: Option<&str>) {
        let mut sink = io::sink();

        let line = a.as_bytes().read_line().unwrap();
        let pass = a.as_bytes().read_passwd(&mut sink).unwrap();

        // godammit rustc

        assert_eq!(line, pass);

        if let Some(l) = line {
            assert_eq!(Some(l.as_str()), b);
        } else {
            assert!(b.is_none());
        }
    }

    #[test]
    fn test_read() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";

        line_match(test1, Some(test1));
        line_match(test2, Some(test2));
    }

    #[test]
    fn test_backspace() {
        line_match("this is the\x7f first\x7f\x7f test", Some("this is th fir test"));
        line_match("this is the seco\x7fnd test\x7f", Some("this is the secnd tes"));
    }

    #[test]
    fn test_end() {
        line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ", Some("abc"));
        line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA", Some("hello"));
    }

    #[test]
    fn test_abort() {
        line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None);
        line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None);
    }
}
<commit_msg>fix wrong range used<commit_after>use std::io::{self, Read, Write};

use IntoRawMode;

/// A key.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Key {
    /// Backspace.
    Backspace,
    /// Left arrow.
    Left,
    /// Right arrow.
    Right,
    /// Up arrow.
    Up,
    /// Down arrow.
    Down,
    /// Home key.
    Home,
    /// End key.
    End,
    /// Page Up key.
    PageUp,
    /// Page Down key.
    PageDown,
    /// Delete key.
    Delete,
    /// Insert key.
    Insert,
    /// Function keys.
    ///
    /// Only function keys 1 through 12 are supported.
    F(u8),
    /// Normal character.
    Char(char),
    /// Alt modified character.
    Alt(char),
    /// Ctrl modified character.
    ///
    /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals.
    Ctrl(char),
    /// Invalid character code.
    Invalid,
    /// Null byte.
    Null,

    #[allow(missing_docs)]
    #[doc(hidden)]
    __IsNotComplete
}

/// An iterator over input keys.
#[cfg(feature = "nightly")]
pub struct Keys<I> {
    chars: I,
}

#[cfg(feature = "nightly")]
impl<I: Iterator<Item = Result<char, io::CharsError>>> Iterator for Keys<I> {
    type Item = Result<Key, io::CharsError>;

    fn next(&mut self) -> Option<Result<Key, io::CharsError>> {
        Some(match self.chars.next() {
            Some(Ok('\x1B')) => Ok(match self.chars.next() {
                Some(Ok('O')) => match self.chars.next() {
                    Some(Ok('P')) => Key::F(1),
                    Some(Ok('Q')) => Key::F(2),
                    Some(Ok('R')) => Key::F(3),
                    Some(Ok('S')) => Key::F(4),
                    _ => Key::Invalid,
                },
                Some(Ok('[')) => match self.chars.next() {
                    Some(Ok('D')) => Key::Left,
                    Some(Ok('C')) => Key::Right,
                    Some(Ok('A')) => Key::Up,
                    Some(Ok('B')) => Key::Down,
                    Some(Ok('H')) => Key::Home,
                    Some(Ok('F')) => Key::End,
                    Some(Ok(c @ '1' ... '8')) => match self.chars.next() {
                        Some(Ok('~')) => match c {
                            '1' | '7' => Key::Home,
                            '2' | '8' => Key::Insert,
                            '3' => Key::Delete,
                            '4' => Key::End,
                            '5' => Key::PageUp,
                            '6' => Key::PageDown,
                            _ => Key::Invalid,
                        },
                        Some(Ok(k @ '0' ... '9')) => match self.chars.next() {
                            Some(Ok('~')) => match 10 * (c as u8 - b'0') + (k as u8 - b'0') {
                                v @ 11 ... 15 => Key::F(v - 10),
                                v @ 17 ... 21 => Key::F(v - 11),
                                v @ 23 ... 24 => Key::F(v - 12),
                                _ => Key::Invalid,
                            },
                            _ => Key::Invalid,
                        },
                        _ => Key::Invalid,
                    },
                    _ => Key::Invalid,
                },
                Some(Ok(c)) => Key::Alt(c),
                Some(Err(_)) | None => Key::Invalid,
            }),
            Some(Ok('\n')) | Some(Ok('\r')) => Ok(Key::Char('\n')),
            Some(Ok('\t')) => Ok(Key::Char('\t')),
            Some(Ok('\x7F')) => Ok(Key::Backspace),
            Some(Ok(c @ '\x01' ... '\x1A')) => Ok(Key::Ctrl((c as u8 - 0x1  + b'a') as char)),
            Some(Ok(c @ '\x1C' ... '\x1F')) => Ok(Key::Ctrl((c as u8 - 0x1C + b'4') as char)),
            Some(Ok('\0')) => Ok(Key::Null),
            Some(Ok(c)) => Ok(Key::Char(c)),
            Some(Err(e)) => Err(e),
            None => return None,
        })
    }
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over key inputs.
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<io::Chars<Self>> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read> TermRead for R {
    #[cfg(feature = "nightly")]
    fn keys(self) -> Keys<io::Chars<R>> {
        Keys {
            chars: self.chars(),
        }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => { buf.pop(); },
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

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

    #[cfg(feature = "nightly")]
    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next().unwrap().unwrap(), Key::Alt('a'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('y'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('o'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Backspace);
        assert_eq!(i.next().unwrap().unwrap(), Key::Left);
        assert!(i.next().is_none());
    }

    fn line_match(a: &str, b: Option<&str>) {
        let mut sink = io::sink();

        let line = a.as_bytes().read_line().unwrap();
        let pass = a.as_bytes().read_passwd(&mut sink).unwrap();

        // godammit rustc

        assert_eq!(line, pass);

        if let Some(l) = line {
            assert_eq!(Some(l.as_str()), b);
        } else {
            assert!(b.is_none());
        }
    }

    #[test]
    fn test_read() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";

        line_match(test1, Some(test1));
        line_match(test2, Some(test2));
    }

    #[test]
    fn test_backspace() {
        line_match("this is the\x7f first\x7f\x7f test", Some("this is th fir test"));
        line_match("this is the seco\x7fnd test\x7f", Some("this is the secnd tes"));
    }

    #[test]
    fn test_end() {
        line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ", Some("abc"));
        line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA", Some("hello"));
    }

    #[test]
    fn test_abort() {
        line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None);
        line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None);
    }
}
<|endoftext|>