<commit_before>//! Errors for `irc` crate using `failure`.

use std::io::Error as IoError;
use std::sync::mpsc::RecvError;

use thiserror::Error;
use tokio::sync::mpsc::error::{SendError, TrySendError};

#[cfg(feature = "tls-rust")]
use tokio_rustls::webpki::InvalidDNSNameError;

use crate::proto::error::{MessageParseError, ProtocolError};

/// A specialized `Result` type for the `irc` crate.
pub type Result<T, E = Error> = std::result::Result<T, E>;

/// The main crate-wide error type.
#[derive(Debug, Error)]
pub enum Error {
    /// An internal I/O error.
    #[error("an io error occurred")]
    Io(#[source] IoError),

    /// An internal proxy error.
    #[cfg(feature = "proxy")]
    #[error("a proxy error occurred")]
    Proxy(tokio_socks::Error),

    /// An internal TLS error.
    #[cfg(feature = "tls-native")]
    #[error("a TLS error occurred")]
    Tls(#[source] native_tls::Error),

    /// An internal DNS error.
    #[cfg(feature = "tls-rust")]
    #[error("a DNS error occurred")]
    Dns(#[source] InvalidDNSNameError),

    /// An internal synchronous channel closed.
    #[error("a sync channel closed")]
    SyncChannelClosed(#[source] RecvError),

    /// An internal asynchronous channel closed.
    #[error("an async channel closed")]
    AsyncChannelClosed,

    /// An internal oneshot channel closed.
    #[error("a oneshot channel closed")]
    OneShotCanceled,

    /// Error for invalid configurations.
    #[error("invalid config: {}", path)]
    InvalidConfig {
        /// The path to the configuration, or "<none>" if none specified.
        path: String,
        /// The detailed configuration error.
        #[source]
        cause: ConfigError,
    },

    /// Error for invalid messages.
    #[error("invalid message: {}", string)]
    InvalidMessage {
        /// The string that failed to parse.
        string: String,
        /// The detailed message parsing error.
        #[source]
        cause: MessageParseError,
    },

    /// Mutex for a logged transport was poisoned making the log inaccessible.
    #[error("mutex for a logged transport was poisoned")]
    PoisonedLog,

    /// Ping timed out due to no response.
    #[error("connection reset: no ping response")]
    PingTimeout,

    /// Failed to lookup an unknown codec.
    #[error("unknown codec: {}", codec)]
    UnknownCodec {
        /// The attempted codec.
        codec: String,
    },

    /// Failed to encode or decode something with the given codec.
    #[error("codec {} failed: {}", codec, data)]
    CodecFailed {
        /// The canonical codec name.
        codec: &'static str,
        /// The data that failed to encode or decode.
        data: String,
    },

    /// All specified nicknames were in use or unusable.
    #[error("none of the specified nicknames were usable")]
    NoUsableNick,

    /// Stream has already been configured.
    #[error("stream has already been configured")]
    StreamAlreadyConfigured,
}

/// Errors that occur with configurations.
#[derive(Debug, Error)]
pub enum ConfigError {
    /// Failed to parse as TOML.
    #[cfg(feature = "toml_config")]
    #[error("invalid toml")]
    InvalidToml(#[source] TomlError),

    /// Failed to parse as JSON.
    #[cfg(feature = "json_config")]
    #[error("invalid json")]
    InvalidJson(#[source] serde_json::Error),

    /// Failed to parse as YAML.
    #[cfg(feature = "yaml_config")]
    #[error("invalid yaml")]
    InvalidYaml(#[source] serde_yaml::Error),

    /// Failed to parse the given format because it was disabled at compile-time.
    #[error("config format disabled: {}", format)]
    ConfigFormatDisabled {
        /// The disabled file format.
        format: &'static str,
    },

    /// Could not identify the given file format.
    #[error("config format unknown: {}", format)]
    UnknownConfigFormat {
        /// The unknown file extension.
        format: String,
    },

    /// File was missing an extension to identify file format.
    #[error("missing format extension")]
    MissingExtension,

    /// Configuration does not specify a nickname.
    #[error("nickname not specified")]
    NicknameNotSpecified,

    /// Configuration does not specify a server.
    #[error("server not specified")]
    ServerNotSpecified,
}

/// A wrapper that combines toml's serialization and deserialization errors.
#[cfg(feature = "toml_config")]
#[derive(Debug, Error)]
pub enum TomlError {
    /// A TOML deserialization error.
    #[error("deserialization failed")]
    Read(#[source] toml::de::Error),
    /// A TOML serialization error.
    #[error("serialization failed")]
    Write(#[source] toml::ser::Error),
}

impl From<ProtocolError> for Error {
    fn from(e: ProtocolError) -> Error {
        match e {
            ProtocolError::Io(e) => Error::Io(e),
            ProtocolError::InvalidMessage { string, cause } => {
                Error::InvalidMessage { string, cause }
            }
        }
    }
}

impl From<IoError> for Error {
    fn from(e: IoError) -> Error {
        Error::Io(e)
    }
}

#[cfg(feature = "proxy")]
impl From<tokio_socks::Error> for Error {
    fn from(e: tokio_socks::Error) -> Error {
        Error::Proxy(e)
    }
}

#[cfg(feature = "tls-native")]
impl From<native_tls::Error> for Error {
    fn from(e: native_tls::Error) -> Error {
        Error::Tls(e)
    }
}

#[cfg(feature = "tls-rust")]
impl From<InvalidDNSNameError> for Error {
    fn from(e: InvalidDNSNameError) -> Error {
        Error::Dns(e)
    }
}

impl From<RecvError> for Error {
    fn from(e: RecvError) -> Error {
        Error::SyncChannelClosed(e)
    }
}

impl<T> From<SendError<T>> for Error {
    fn from(_: SendError<T>) -> Error {
        Error::AsyncChannelClosed
    }
}

impl<T> From<TrySendError<T>> for Error {
    fn from(_: TrySendError<T>) -> Error {
        Error::AsyncChannelClosed
    }
}
<commit_msg>add ConfigError variant for missing files<commit_after>//! Errors for `irc` crate using `failure`.

use std::io::Error as IoError;
use std::sync::mpsc::RecvError;

use thiserror::Error;
use tokio::sync::mpsc::error::{SendError, TrySendError};

#[cfg(feature = "tls-rust")]
use tokio_rustls::webpki::InvalidDNSNameError;

use crate::proto::error::{MessageParseError, ProtocolError};

/// A specialized `Result` type for the `irc` crate.
pub type Result<T, E = Error> = std::result::Result<T, E>;

/// The main crate-wide error type.
#[derive(Debug, Error)]
pub enum Error {
    /// An internal I/O error.
    #[error("an io error occurred")]
    Io(#[source] IoError),

    /// An internal proxy error.
    #[cfg(feature = "proxy")]
    #[error("a proxy error occurred")]
    Proxy(tokio_socks::Error),

    /// An internal TLS error.
    #[cfg(feature = "tls-native")]
    #[error("a TLS error occurred")]
    Tls(#[source] native_tls::Error),

    /// An internal DNS error.
    #[cfg(feature = "tls-rust")]
    #[error("a DNS error occurred")]
    Dns(#[source] InvalidDNSNameError),

    /// An internal synchronous channel closed.
    #[error("a sync channel closed")]
    SyncChannelClosed(#[source] RecvError),

    /// An internal asynchronous channel closed.
    #[error("an async channel closed")]
    AsyncChannelClosed,

    /// An internal oneshot channel closed.
    #[error("a oneshot channel closed")]
    OneShotCanceled,

    /// Error for invalid configurations.
    #[error("invalid config: {}", path)]
    InvalidConfig {
        /// The path to the configuration, or "<none>" if none specified.
        path: String,
        /// The detailed configuration error.
        #[source]
        cause: ConfigError,
    },

    /// Error for invalid messages.
    #[error("invalid message: {}", string)]
    InvalidMessage {
        /// The string that failed to parse.
        string: String,
        /// The detailed message parsing error.
        #[source]
        cause: MessageParseError,
    },

    /// Mutex for a logged transport was poisoned making the log inaccessible.
    #[error("mutex for a logged transport was poisoned")]
    PoisonedLog,

    /// Ping timed out due to no response.
    #[error("connection reset: no ping response")]
    PingTimeout,

    /// Failed to lookup an unknown codec.
    #[error("unknown codec: {}", codec)]
    UnknownCodec {
        /// The attempted codec.
        codec: String,
    },

    /// Failed to encode or decode something with the given codec.
    #[error("codec {} failed: {}", codec, data)]
    CodecFailed {
        /// The canonical codec name.
        codec: &'static str,
        /// The data that failed to encode or decode.
        data: String,
    },

    /// All specified nicknames were in use or unusable.
    #[error("none of the specified nicknames were usable")]
    NoUsableNick,

    /// Stream has already been configured.
    #[error("stream has already been configured")]
    StreamAlreadyConfigured,
}

/// Errors that occur with configurations.
#[derive(Debug, Error)]
pub enum ConfigError {
    /// Failed to parse as TOML.
    #[cfg(feature = "toml_config")]
    #[error("invalid toml")]
    InvalidToml(#[source] TomlError),

    /// Failed to parse as JSON.
    #[cfg(feature = "json_config")]
    #[error("invalid json")]
    InvalidJson(#[source] serde_json::Error),

    /// Failed to parse as YAML.
    #[cfg(feature = "yaml_config")]
    #[error("invalid yaml")]
    InvalidYaml(#[source] serde_yaml::Error),

    /// Failed to parse the given format because it was disabled at compile-time.
    #[error("config format disabled: {}", format)]
    ConfigFormatDisabled {
        /// The disabled file format.
        format: &'static str,
    },

    /// Could not identify the given file format.
    #[error("config format unknown: {}", format)]
    UnknownConfigFormat {
        /// The unknown file extension.
        format: String,
    },

    /// File was missing an extension to identify file format.
    #[error("missing format extension")]
    MissingExtension,

    /// Configuration does not specify a nickname.
    #[error("nickname not specified")]
    NicknameNotSpecified,

    /// Configuration does not specify a server.
    #[error("server not specified")]
    ServerNotSpecified,

    /// The specified file could not be read.
    #[error("could not read file {}", file)]
    FileMissing {
        /// The supposed location of the file.
        file: String,
    },
}

/// A wrapper that combines toml's serialization and deserialization errors.
#[cfg(feature = "toml_config")]
#[derive(Debug, Error)]
pub enum TomlError {
    /// A TOML deserialization error.
    #[error("deserialization failed")]
    Read(#[source] toml::de::Error),
    /// A TOML serialization error.
    #[error("serialization failed")]
    Write(#[source] toml::ser::Error),
}

impl From<ProtocolError> for Error {
    fn from(e: ProtocolError) -> Error {
        match e {
            ProtocolError::Io(e) => Error::Io(e),
            ProtocolError::InvalidMessage { string, cause } => {
                Error::InvalidMessage { string, cause }
            }
        }
    }
}

impl From<IoError> for Error {
    fn from(e: IoError) -> Error {
        Error::Io(e)
    }
}

#[cfg(feature = "proxy")]
impl From<tokio_socks::Error> for Error {
    fn from(e: tokio_socks::Error) -> Error {
        Error::Proxy(e)
    }
}

#[cfg(feature = "tls-native")]
impl From<native_tls::Error> for Error {
    fn from(e: native_tls::Error) -> Error {
        Error::Tls(e)
    }
}

#[cfg(feature = "tls-rust")]
impl From<InvalidDNSNameError> for Error {
    fn from(e: InvalidDNSNameError) -> Error {
        Error::Dns(e)
    }
}

impl From<RecvError> for Error {
    fn from(e: RecvError) -> Error {
        Error::SyncChannelClosed(e)
    }
}

impl<T> From<SendError<T>> for Error {
    fn from(_: SendError<T>) -> Error {
        Error::AsyncChannelClosed
    }
}

impl<T> From<TrySendError<T>> for Error {
    fn from(_: TrySendError<T>) -> Error {
        Error::AsyncChannelClosed
    }
}
<|endoftext|>


<commit_before>//! Contains error type for handling I/O and Errno errors
#[cfg(windows)]
use std::char;
use std::error::Error;
use std::fmt;
use std::io;

/// The error type for Rustyline errors that can arise from
/// I/O related errors or Errno when using the nix-rust library
// #[non_exhaustive]
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
#[non_exhaustive]
pub enum ReadlineError {
    /// I/O Error
    Io(io::Error),
    /// EOF (VEOF / Ctrl-D)
    Eof,
    /// Interrupt signal (VINTR / VQUIT / Ctrl-C)
    Interrupted,
    /// Unix Error from syscall
    #[cfg(unix)]
    Errno(nix::Error),
    /// Error generated on WINDOW_BUFFER_SIZE_EVENT / SIGWINCH signal
    WindowResized,
    /// Like Utf8Error on unix
    #[cfg(windows)]
    Decode(char::DecodeUtf16Error),
    /// Something went wrong calling a Windows API
    #[cfg(windows)]
    SystemError(clipboard_win::SystemError),
}

impl fmt::Display for ReadlineError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ReadlineError::Io(ref err) => err.fmt(f),
            ReadlineError::Eof => write!(f, "EOF"),
            ReadlineError::Interrupted => write!(f, "Interrupted"),
            #[cfg(unix)]
            ReadlineError::Errno(ref err) => err.fmt(f),
            ReadlineError::WindowResized => write!(f, "WindowResized"),
            #[cfg(windows)]
            ReadlineError::Decode(ref err) => err.fmt(f),
            #[cfg(windows)]
            ReadlineError::SystemError(ref err) => err.fmt(f),
        }
    }
}

impl Error for ReadlineError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            ReadlineError::Io(ref err) => Some(err),
            ReadlineError::Eof => None,
            ReadlineError::Interrupted => None,
            #[cfg(unix)]
            ReadlineError::Errno(ref err) => Some(err),
            ReadlineError::WindowResized => None,
            #[cfg(windows)]
            ReadlineError::Decode(ref err) => Some(err),
            #[cfg(windows)]
            ReadlineError::SystemError(ref err) => Some(err),
        }
    }
}

#[cfg(unix)]
#[derive(Debug)]
pub(crate) struct WindowResizedError;
#[cfg(unix)]
impl fmt::Display for WindowResizedError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "WindowResized")
    }
}
#[cfg(unix)]
impl Error for WindowResizedError {}

impl From<io::Error> for ReadlineError {
    fn from(err: io::Error) -> Self {
        #[cfg(unix)]
        if err.kind() == io::ErrorKind::Interrupted {
            if let Some(e) = err.get_ref() {
                if e.downcast_ref::<WindowResizedError>().is_some() {
                    return ReadlineError::WindowResized;
                }
            }
        }
        ReadlineError::Io(err)
    }
}

impl From<io::ErrorKind> for ReadlineError {
    fn from(kind: io::ErrorKind) -> Self {
        ReadlineError::Io(io::Error::from(kind))
    }
}

#[cfg(unix)]
impl From<nix::Error> for ReadlineError {
    fn from(err: nix::Error) -> Self {
        ReadlineError::Errno(err)
    }
}

#[cfg(windows)]
impl From<char::DecodeUtf16Error> for ReadlineError {
    fn from(err: char::DecodeUtf16Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err))
    }
}

#[cfg(windows)]
impl From<std::string::FromUtf8Error> for ReadlineError {
    fn from(err: std::string::FromUtf8Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err))
    }
}

#[cfg(unix)]
impl From<fmt::Error> for ReadlineError {
    fn from(err: fmt::Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::Other, err))
    }
}

#[cfg(windows)]
impl From<clipboard_win::SystemError> for ReadlineError {
    fn from(err: clipboard_win::SystemError) -> Self {
        ReadlineError::SystemError(err)
    }
}
<commit_msg>Fix Windows build<commit_after>//! Contains error type for handling I/O and Errno errors
#[cfg(windows)]
use std::char;
use std::error::Error;
use std::fmt;
use std::io;

/// The error type for Rustyline errors that can arise from
/// I/O related errors or Errno when using the nix-rust library
// #[non_exhaustive]
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
#[non_exhaustive]
pub enum ReadlineError {
    /// I/O Error
    Io(io::Error),
    /// EOF (VEOF / Ctrl-D)
    Eof,
    /// Interrupt signal (VINTR / VQUIT / Ctrl-C)
    Interrupted,
    /// Unix Error from syscall
    #[cfg(unix)]
    Errno(nix::Error),
    /// Error generated on WINDOW_BUFFER_SIZE_EVENT / SIGWINCH signal
    WindowResized,
    /// Like Utf8Error on unix
    #[cfg(windows)]
    Decode(char::DecodeUtf16Error),
    /// Something went wrong calling a Windows API
    #[cfg(windows)]
    SystemError(clipboard_win::SystemError),
}

impl fmt::Display for ReadlineError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ReadlineError::Io(ref err) => err.fmt(f),
            ReadlineError::Eof => write!(f, "EOF"),
            ReadlineError::Interrupted => write!(f, "Interrupted"),
            #[cfg(unix)]
            ReadlineError::Errno(ref err) => err.fmt(f),
            ReadlineError::WindowResized => write!(f, "WindowResized"),
            #[cfg(windows)]
            ReadlineError::Decode(ref err) => err.fmt(f),
            #[cfg(windows)]
            ReadlineError::SystemError(ref err) => err.fmt(f),
        }
    }
}

impl Error for ReadlineError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match *self {
            ReadlineError::Io(ref err) => Some(err),
            ReadlineError::Eof => None,
            ReadlineError::Interrupted => None,
            #[cfg(unix)]
            ReadlineError::Errno(ref err) => Some(err),
            ReadlineError::WindowResized => None,
            #[cfg(windows)]
            ReadlineError::Decode(ref err) => Some(err),
            #[cfg(windows)]
            ReadlineError::SystemError(_) => None,
        }
    }
}

#[cfg(unix)]
#[derive(Debug)]
pub(crate) struct WindowResizedError;
#[cfg(unix)]
impl fmt::Display for WindowResizedError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "WindowResized")
    }
}
#[cfg(unix)]
impl Error for WindowResizedError {}

impl From<io::Error> for ReadlineError {
    fn from(err: io::Error) -> Self {
        #[cfg(unix)]
        if err.kind() == io::ErrorKind::Interrupted {
            if let Some(e) = err.get_ref() {
                if e.downcast_ref::<WindowResizedError>().is_some() {
                    return ReadlineError::WindowResized;
                }
            }
        }
        ReadlineError::Io(err)
    }
}

impl From<io::ErrorKind> for ReadlineError {
    fn from(kind: io::ErrorKind) -> Self {
        ReadlineError::Io(io::Error::from(kind))
    }
}

#[cfg(unix)]
impl From<nix::Error> for ReadlineError {
    fn from(err: nix::Error) -> Self {
        ReadlineError::Errno(err)
    }
}

#[cfg(windows)]
impl From<char::DecodeUtf16Error> for ReadlineError {
    fn from(err: char::DecodeUtf16Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err))
    }
}

#[cfg(windows)]
impl From<std::string::FromUtf8Error> for ReadlineError {
    fn from(err: std::string::FromUtf8Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::InvalidData, err))
    }
}

#[cfg(unix)]
impl From<fmt::Error> for ReadlineError {
    fn from(err: fmt::Error) -> Self {
        ReadlineError::Io(io::Error::new(io::ErrorKind::Other, err))
    }
}

#[cfg(windows)]
impl From<clipboard_win::SystemError> for ReadlineError {
    fn from(err: clipboard_win::SystemError) -> Self {
        ReadlineError::SystemError(err)
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        unsafe {
            let backtrace = match error.backtrace() {
                Some(_) => None,
                None => Some(Backtrace::capture()),
            };
            let obj: TraitObject = mem::transmute(&error as &dyn StdError);
            let vtable = obj.vtable;
            let inner = ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            };
            Error {
                inner: mem::transmute(Box::new(inner)),
            }
        }
    }

    /// View this error object as the underlying error.
    pub fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of errors contained by this Error.
    ///
    /// This iterator will visit every error in the "cause chain" of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn errors(&self) -> Errors<'_> {
        Errors {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E: Display + Debug + Send + Sync + 'static>(&self) -> bool {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E: Display + Debug + Send + Sync + 'static>(self) -> Result<E, Error> {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E: Display + Debug + Send + Sync + 'static>(&self) -> Option<&E> {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E: Display + Debug + Send + Sync + 'static>(&mut self) -> Option<&mut E> {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E: StdError + Send + Sync + 'static> From<E> for Error {
    fn from(error: E) -> Error {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.errors().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_BACKTRACE=1 environment variable \
                     to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M: Display + Debug>(M);

impl<M: Display + Debug> Debug for MessageError<M> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M: Display + Debug> Display for MessageError<M> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M: Display + Debug + 'static> StdError for MessageError<M> {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &self.error,
                vtable: self.vtable,
            })
        }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &mut self.error,
                vtable: self.vtable,
            })
        }
    }
}

/// Iterator of errors in an `Error`.
pub struct Errors<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Errors<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

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

    use std::marker::Unpin;
    use std::mem;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[allow(dead_code)]
    fn assert_error_autotraits()
    where
        Error: Unpin + Send + Sync + 'static,
    {
    }

    #[test]
    fn destructors_work() {
        use std::sync::*;

        #[derive(Debug)]
        struct HasDrop(Box<Arc<Mutex<bool>>>);
        impl StdError for HasDrop {}
        impl Display for HasDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }
        impl Drop for HasDrop {
            fn drop(&mut self) {
                let mut has_dropped = self.0.lock().unwrap();
                assert!(!*has_dropped);
                *has_dropped = true;
            }
        }

        let has_dropped = Arc::new(Mutex::new(false));

        drop(Error::from(HasDrop(Box::new(has_dropped.clone()))));

        assert!(*has_dropped.lock().unwrap());
    }
}
<commit_msg>Un-wrap backtrace disabled message for easier grepping<commit_after>use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        unsafe {
            let backtrace = match error.backtrace() {
                Some(_) => None,
                None => Some(Backtrace::capture()),
            };
            let obj: TraitObject = mem::transmute(&error as &dyn StdError);
            let vtable = obj.vtable;
            let inner = ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            };
            Error {
                inner: mem::transmute(Box::new(inner)),
            }
        }
    }

    /// View this error object as the underlying error.
    pub fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of errors contained by this Error.
    ///
    /// This iterator will visit every error in the "cause chain" of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn errors(&self) -> Errors<'_> {
        Errors {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E: Display + Debug + Send + Sync + 'static>(&self) -> bool {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E: Display + Debug + Send + Sync + 'static>(self) -> Result<E, Error> {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E: Display + Debug + Send + Sync + 'static>(&self) -> Option<&E> {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E: Display + Debug + Send + Sync + 'static>(&mut self) -> Option<&mut E> {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E: StdError + Send + Sync + 'static> From<E> for Error {
    fn from(error: E) -> Error {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.errors().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M: Display + Debug>(M);

impl<M: Display + Debug> Debug for MessageError<M> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M: Display + Debug> Display for MessageError<M> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M: Display + Debug + 'static> StdError for MessageError<M> {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &self.error,
                vtable: self.vtable,
            })
        }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &mut self.error,
                vtable: self.vtable,
            })
        }
    }
}

/// Iterator of errors in an `Error`.
pub struct Errors<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Errors<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

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

    use std::marker::Unpin;
    use std::mem;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[allow(dead_code)]
    fn assert_error_autotraits()
    where
        Error: Unpin + Send + Sync + 'static,
    {
    }

    #[test]
    fn destructors_work() {
        use std::sync::*;

        #[derive(Debug)]
        struct HasDrop(Box<Arc<Mutex<bool>>>);
        impl StdError for HasDrop {}
        impl Display for HasDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }
        impl Drop for HasDrop {
            fn drop(&mut self) {
                let mut has_dropped = self.0.lock().unwrap();
                assert!(!*has_dropped);
                *has_dropped = true;
            }
        }

        let has_dropped = Arc::new(Mutex::new(false));

        drop(Error::from(HasDrop(Box::new(has_dropped.clone()))));

        assert!(*has_dropped.lock().unwrap());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(target_arch = "wasm32", allow(unused))]
use std::error::Error as StdError;
use std::fmt;
use std::io;

use crate::{StatusCode, Url};

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = std::result::Result<T, Error>;

/// The Errors that may occur when processing a `Request`.
pub struct Error {
    inner: Box<Inner>,
}

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

struct Inner {
    kind: Kind,
    source: Option<BoxError>,
    url: Option<Url>,
}

impl Error {
    pub(crate) fn new<E>(kind: Kind, source: Option<E>) -> Error
    where
        E: Into<BoxError>,
    {
        Error {
            inner: Box::new(Inner {
                kind,
                source: source.map(Into::into),
                url: None,
            }),
        }
    }

    /// Returns a possible URL related to this error.
    ///
    /// # Examples
    ///
    /// ```
    /// # async fn run() {
    /// // displays last stop of a redirect loop
    /// let response = reqwest::get("http://site.with.redirect.loop").await;
    /// if let Err(e) = response {
    ///     if e.is_redirect() {
    ///         if let Some(final_stop) = e.url() {
    ///             println!("redirect loop at {}", final_stop);
    ///         }
    ///     }
    /// }
    /// # }
    /// ```
    pub fn url(&self) -> Option<&Url> {
        self.inner.url.as_ref()
    }

    /// Returns true if the error is from a type Builder.
    pub fn is_builder(&self) -> bool {
        match self.inner.kind {
            Kind::Builder => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    pub fn is_redirect(&self) -> bool {
        match self.inner.kind {
            Kind::Redirect => true,
            _ => false,
        }
    }

    /// Returns true if the error is from `Response::error_for_status`.
    pub fn is_status(&self) -> bool {
        match self.inner.kind {
            Kind::Status(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is related to a timeout.
    pub fn is_timeout(&self) -> bool {
        let mut source = self.source();

        while let Some(err) = source {
            if err.is::<TimedOut>() {
                return true;
            }
            source = err.source();
        }

        false
    }

    /// Returns the status code, if the error was generated from a response.
    pub fn status(&self) -> Option<StatusCode> {
        match self.inner.kind {
            Kind::Status(code) => Some(code),
            _ => None,
        }
    }

    // private

    pub(crate) fn with_url(mut self, url: Url) -> Error {
        self.inner.url = Some(url);
        self
    }

    #[allow(unused)]
    pub(crate) fn into_io(self) -> io::Error {
        io::Error::new(io::ErrorKind::Other, self)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut builder = f.debug_struct("reqwest::Error");

        builder.field("kind", &self.inner.kind);

        if let Some(ref url) = self.inner.url {
            builder.field("url", url);
        }
        if let Some(ref source) = self.inner.source {
            builder.field("source", source);
        }

        builder.finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        struct ForUrl<'a>(Option<&'a Url>);

        impl fmt::Display for ForUrl<'_> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                if let Some(url) = self.0 {
                    write!(f, " for url ({})", url.as_str())
                } else {
                    Ok(())
                }
            }
        }

        match self.inner.kind {
            Kind::Builder => f.write_str("builder error")?,
            Kind::Request => f.write_str("error sending request")?,
            Kind::Body => f.write_str("request or response body error")?,
            Kind::Decode => f.write_str("error decoding response body")?,
            Kind::Redirect => f.write_str("error following redirect")?,
            Kind::Status(ref code) => {
                let prefix = if code.is_client_error() {
                    "HTTP status client error"
                } else {
                    debug_assert!(code.is_server_error());
                    "HTTP status server error"
                };
                write!(f, "{} ({})", prefix, code)?;
            }
        };

        ForUrl(self.inner.url.as_ref()).fmt(f)?;

        if let Some(ref e) = self.inner.source {
            write!(f, ": {}", e)?;
        }

        Ok(())
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.inner.source.as_ref().map(|e| &**e as _)
    }
}

#[cfg(target_arch = "wasm32")]
impl From<crate::error::Error> for wasm_bindgen::JsValue {
    fn from(err: Error) -> wasm_bindgen::JsValue {
        js_sys::Error::from(err).into()
    }
}

#[cfg(target_arch = "wasm32")]
impl From<crate::error::Error> for js_sys::Error {
    fn from(err: Error) -> js_sys::Error {
        js_sys::Error::new(&format!("{}", err))
    }
}

#[derive(Debug)]
pub(crate) enum Kind {
    Builder,
    Request,
    Redirect,
    Status(StatusCode),
    Body,
    Decode,
}

// constructors

pub(crate) fn builder<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Builder, Some(e))
}

pub(crate) fn body<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Body, Some(e))
}

pub(crate) fn decode<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Decode, Some(e))
}

pub(crate) fn request<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Request, Some(e))
}

pub(crate) fn redirect<E: Into<BoxError>>(e: E, url: Url) -> Error {
    Error::new(Kind::Redirect, Some(e)).with_url(url)
}

pub(crate) fn status_code(url: Url, status: StatusCode) -> Error {
    Error::new(Kind::Status(status), None::<Error>).with_url(url)
}

pub(crate) fn url_bad_scheme(url: Url) -> Error {
    Error::new(Kind::Builder, Some("URL scheme is not allowed")).with_url(url)
}

if_wasm! {
    pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {
        format!("{:?}", js_val).into()
    }
}

// io::Error helpers

#[allow(unused)]
pub(crate) fn into_io(e: Error) -> io::Error {
    e.into_io()
}

#[allow(unused)]
pub(crate) fn decode_io(e: io::Error) -> Error {
    if e.get_ref().map(|r| r.is::<Error>()).unwrap_or(false) {
        *e.into_inner()
            .expect("io::Error::get_ref was Some(_)")
            .downcast::<Error>()
            .expect("StdError::is() was true")
    } else {
        decode(e)
    }
}

// internal Error "sources"

#[derive(Debug)]
pub(crate) struct TimedOut;

impl fmt::Display for TimedOut {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("operation timed out")
    }
}

impl StdError for TimedOut {}

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

    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}

    #[test]
    fn test_source_chain() {
        let root = Error::new(Kind::Request, None::<Error>);
        assert!(root.source().is_none());

        let link = super::body(root);
        assert!(link.source().is_some());
        assert_send::<Error>();
        assert_sync::<Error>();
    }

    #[test]
    fn mem_size_of() {
        use std::mem::size_of;
        assert_eq!(size_of::<Error>(), size_of::<usize>());
    }

    #[test]
    fn roundtrip_io_error() {
        let orig = super::request("orig");
        // Convert reqwest::Error into an io::Error...
        let io = orig.into_io();
        // Convert that io::Error back into a reqwest::Error...
        let err = super::decode_io(io);
        // It should have pulled out the original, not nested it...
        match err.inner.kind {
            Kind::Request => (),
            _ => panic!("{:?}", err),
        }
    }

    #[test]
    fn from_unknown_io_error() {
        let orig = io::Error::new(io::ErrorKind::Other, "orly");
        let err = super::decode_io(orig);
        match err.inner.kind {
            Kind::Decode => (),
            _ => panic!("{:?}", err),
        }
    }

    #[test]
    fn is_timeout() {
        let err = super::request(super::TimedOut);
        assert!(err.is_timeout());

        let io = io::Error::new(io::ErrorKind::Other, err);
        let nested = super::request(io);
        assert!(nested.is_timeout());
    }
}
<commit_msg>Error: add functions to check more error types. (#945)<commit_after>#![cfg_attr(target_arch = "wasm32", allow(unused))]
use std::error::Error as StdError;
use std::fmt;
use std::io;

use crate::{StatusCode, Url};

/// A `Result` alias where the `Err` case is `reqwest::Error`.
pub type Result<T> = std::result::Result<T, Error>;

/// The Errors that may occur when processing a `Request`.
pub struct Error {
    inner: Box<Inner>,
}

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

struct Inner {
    kind: Kind,
    source: Option<BoxError>,
    url: Option<Url>,
}

impl Error {
    pub(crate) fn new<E>(kind: Kind, source: Option<E>) -> Error
    where
        E: Into<BoxError>,
    {
        Error {
            inner: Box::new(Inner {
                kind,
                source: source.map(Into::into),
                url: None,
            }),
        }
    }

    /// Returns a possible URL related to this error.
    ///
    /// # Examples
    ///
    /// ```
    /// # async fn run() {
    /// // displays last stop of a redirect loop
    /// let response = reqwest::get("http://site.with.redirect.loop").await;
    /// if let Err(e) = response {
    ///     if e.is_redirect() {
    ///         if let Some(final_stop) = e.url() {
    ///             println!("redirect loop at {}", final_stop);
    ///         }
    ///     }
    /// }
    /// # }
    /// ```
    pub fn url(&self) -> Option<&Url> {
        self.inner.url.as_ref()
    }

    /// Returns true if the error is from a type Builder.
    pub fn is_builder(&self) -> bool {
        match self.inner.kind {
            Kind::Builder => true,
            _ => false,
        }
    }

    /// Returns true if the error is from a `RedirectPolicy`.
    pub fn is_redirect(&self) -> bool {
        match self.inner.kind {
            Kind::Redirect => true,
            _ => false,
        }
    }

    /// Returns true if the error is from `Response::error_for_status`.
    pub fn is_status(&self) -> bool {
        match self.inner.kind {
            Kind::Status(_) => true,
            _ => false,
        }
    }

    /// Returns true if the error is related to a timeout.
    pub fn is_timeout(&self) -> bool {
        let mut source = self.source();

        while let Some(err) = source {
            if err.is::<TimedOut>() {
                return true;
            }
            source = err.source();
        }

        false
    }

    /// Returns true if the error is related to the request
    pub fn is_request(&self) -> bool {
        match self.inner.kind {
            Kind::Request => true,
            _ => false,
        }
    }

    /// Returns true if the error is related to the request or response body
    pub fn is_body(&self) -> bool {
        match self.inner.kind {
            Kind::Body => true,
            _ => false,
        }
    }

    /// Returns true if the error is related to decoding the response's body
    pub fn is_decode(&self) -> bool {
        match self.inner.kind {
            Kind::Decode => true,
            _ => false,
        }
    }

    /// Returns the status code, if the error was generated from a response.
    pub fn status(&self) -> Option<StatusCode> {
        match self.inner.kind {
            Kind::Status(code) => Some(code),
            _ => None,
        }
    }

    // private

    pub(crate) fn with_url(mut self, url: Url) -> Error {
        self.inner.url = Some(url);
        self
    }

    #[allow(unused)]
    pub(crate) fn into_io(self) -> io::Error {
        io::Error::new(io::ErrorKind::Other, self)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut builder = f.debug_struct("reqwest::Error");

        builder.field("kind", &self.inner.kind);

        if let Some(ref url) = self.inner.url {
            builder.field("url", url);
        }
        if let Some(ref source) = self.inner.source {
            builder.field("source", source);
        }

        builder.finish()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        struct ForUrl<'a>(Option<&'a Url>);

        impl fmt::Display for ForUrl<'_> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                if let Some(url) = self.0 {
                    write!(f, " for url ({})", url.as_str())
                } else {
                    Ok(())
                }
            }
        }

        match self.inner.kind {
            Kind::Builder => f.write_str("builder error")?,
            Kind::Request => f.write_str("error sending request")?,
            Kind::Body => f.write_str("request or response body error")?,
            Kind::Decode => f.write_str("error decoding response body")?,
            Kind::Redirect => f.write_str("error following redirect")?,
            Kind::Status(ref code) => {
                let prefix = if code.is_client_error() {
                    "HTTP status client error"
                } else {
                    debug_assert!(code.is_server_error());
                    "HTTP status server error"
                };
                write!(f, "{} ({})", prefix, code)?;
            }
        };

        ForUrl(self.inner.url.as_ref()).fmt(f)?;

        if let Some(ref e) = self.inner.source {
            write!(f, ": {}", e)?;
        }

        Ok(())
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.inner.source.as_ref().map(|e| &**e as _)
    }
}

#[cfg(target_arch = "wasm32")]
impl From<crate::error::Error> for wasm_bindgen::JsValue {
    fn from(err: Error) -> wasm_bindgen::JsValue {
        js_sys::Error::from(err).into()
    }
}

#[cfg(target_arch = "wasm32")]
impl From<crate::error::Error> for js_sys::Error {
    fn from(err: Error) -> js_sys::Error {
        js_sys::Error::new(&format!("{}", err))
    }
}

#[derive(Debug)]
pub(crate) enum Kind {
    Builder,
    Request,
    Redirect,
    Status(StatusCode),
    Body,
    Decode,
}

// constructors

pub(crate) fn builder<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Builder, Some(e))
}

pub(crate) fn body<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Body, Some(e))
}

pub(crate) fn decode<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Decode, Some(e))
}

pub(crate) fn request<E: Into<BoxError>>(e: E) -> Error {
    Error::new(Kind::Request, Some(e))
}

pub(crate) fn redirect<E: Into<BoxError>>(e: E, url: Url) -> Error {
    Error::new(Kind::Redirect, Some(e)).with_url(url)
}

pub(crate) fn status_code(url: Url, status: StatusCode) -> Error {
    Error::new(Kind::Status(status), None::<Error>).with_url(url)
}

pub(crate) fn url_bad_scheme(url: Url) -> Error {
    Error::new(Kind::Builder, Some("URL scheme is not allowed")).with_url(url)
}

if_wasm! {
    pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {
        format!("{:?}", js_val).into()
    }
}

// io::Error helpers

#[allow(unused)]
pub(crate) fn into_io(e: Error) -> io::Error {
    e.into_io()
}

#[allow(unused)]
pub(crate) fn decode_io(e: io::Error) -> Error {
    if e.get_ref().map(|r| r.is::<Error>()).unwrap_or(false) {
        *e.into_inner()
            .expect("io::Error::get_ref was Some(_)")
            .downcast::<Error>()
            .expect("StdError::is() was true")
    } else {
        decode(e)
    }
}

// internal Error "sources"

#[derive(Debug)]
pub(crate) struct TimedOut;

impl fmt::Display for TimedOut {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("operation timed out")
    }
}

impl StdError for TimedOut {}

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

    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}

    #[test]
    fn test_source_chain() {
        let root = Error::new(Kind::Request, None::<Error>);
        assert!(root.source().is_none());

        let link = super::body(root);
        assert!(link.source().is_some());
        assert_send::<Error>();
        assert_sync::<Error>();
    }

    #[test]
    fn mem_size_of() {
        use std::mem::size_of;
        assert_eq!(size_of::<Error>(), size_of::<usize>());
    }

    #[test]
    fn roundtrip_io_error() {
        let orig = super::request("orig");
        // Convert reqwest::Error into an io::Error...
        let io = orig.into_io();
        // Convert that io::Error back into a reqwest::Error...
        let err = super::decode_io(io);
        // It should have pulled out the original, not nested it...
        match err.inner.kind {
            Kind::Request => (),
            _ => panic!("{:?}", err),
        }
    }

    #[test]
    fn from_unknown_io_error() {
        let orig = io::Error::new(io::ErrorKind::Other, "orly");
        let err = super::decode_io(orig);
        match err.inner.kind {
            Kind::Decode => (),
            _ => panic!("{:?}", err),
        }
    }

    #[test]
    fn is_timeout() {
        let err = super::request(super::TimedOut);
        assert!(err.is_timeout());

        let io = io::Error::new(io::ErrorKind::Other, err);
        let nested = super::request(io);
        assert!(nested.is_timeout());
    }
}
<|endoftext|>


<commit_before>use hyper;
use serde_json;
use std;
use url;

use dbtype;

/// Principal error type.
///
/// The public API guarantees only the non-hidden variants and non-hidden
/// variant fields. Do not match against hidden variants or hidden variant
/// fields.
///
#[derive(Debug)]
pub enum Error {
    /// The database already exists.
    DatabaseExists {
        response: ErrorResponse,
    },

    /// JSON-decoding error.
    Decode {
        #[doc(hidden)]
        kind: DecodeKind,
    },

    /// The client request conflicts with an existing document.
    DocumentConflict {
        response: ErrorResponse,
    },

    /// JSON-encoding error.
    Encode {
        #[doc(hidden)]
        cause: serde_json::error::Error,
    },

    /// An internal server error occurred.
    InternalServerError {
        response: ErrorResponse,
    },

    /// The database name is invalid.
    InvalidDatabaseName {
        response: ErrorResponse,
    },

    /// The client request is invalid.
    InvalidRequest {
        response: ErrorResponse,
    },

    /// I/O error with a compile-time description.
    #[doc(hidden)]
    Io {
        description: &'static str,
        cause: std::io::Error,
    },

    /// The CouchDB server responded without a Content-Type header.
    #[doc(hidden)]
    NoContentTypeHeader {
        expected: &'static str,
    },

    /// The resource does not exist.
    NotFound {
        /// CouchDB server response.
        ///
        /// In case of a HEAD request, the response value is None (because the
        /// server doesn't send response content for HEAD requests). Otherwise,
        /// the response value is Some.
        response: Option<ErrorResponse>,
    },

    /// Channel-receiver error with a compile-time description and thread-join
    /// error.
    #[doc(hidden)]
    ReceiveFromThread {
        description: &'static str,
        cause: std::sync::mpsc::RecvError,
    },

    /// HTTP-transport error.
    Transport {
        #[doc(hidden)]
        kind: TransportKind,
    },

    /// The client is unauthorized to carry out the operation.
    Unauthorized {
        response: ErrorResponse,
    },

    /// The CouchDB server responded with a Content-Type header that the client
    /// didn't expect.
    #[doc(hidden)]
    UnexpectedContentTypeHeader {
        expected: &'static str,
        got: String,
    },

    /// The CouchDB server responded with an HTTP status code that the client
    /// didn't expect.
    #[doc(hidden)]
    UnexpectedHttpStatus {
        got: hyper::status::StatusCode,
    },

    /// URI-parse error.
    UriParse {
        #[doc(hidden)]
        cause: url::ParseError,
    },
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            DatabaseExists { .. } => "The database already exists",
            Decode { .. } => "The client failed to decode a JSON response from CouchDB server",
            DocumentConflict { .. } => "The client request conflicts with an existing document",
            Encode { .. } => "The client failed to encode a JSON request to CouchDB server",
            InternalServerError { .. } => "An internal server error occurred",
            InvalidDatabaseName { .. } => "The database name is invalid",
            InvalidRequest { .. } => "The client request is invalid",
            Io { ref description, .. } => description,
            NoContentTypeHeader { .. } => "The CouchDB server responded without a Content-Type header",
            NotFound { .. } => "The resource does not exist",
            ReceiveFromThread { ref description, .. } => description,
            Transport { .. } => "An HTTP transport error occurred",
            Unauthorized { .. } => "The client is unauthorized to carry out the operation",
            UnexpectedContentTypeHeader { .. } => {
                "The CouchDB server responded with a Content-Type header the client did not expect"
            }
            UnexpectedHttpStatus { .. } => {
                "The CouchDB server responded with an HTTP status code the client did not expect"
            }
            UriParse { .. } => "Invalid URI argument",
        }
    }

    fn cause(&self) -> std::option::Option<&std::error::Error> {
        use self::Error::*;
        match *self {
            DatabaseExists { .. } => None,
            Decode { ref kind } => kind.cause(),
            DocumentConflict { .. } => None,
            Encode { ref cause } => Some(cause),
            InternalServerError { .. } => None,
            InvalidDatabaseName { .. } => None,
            InvalidRequest { .. } => None,
            Io { ref cause, .. } => Some(cause),
            NoContentTypeHeader { .. } => None,
            NotFound { .. } => None,
            ReceiveFromThread { ref cause, .. } => Some(cause),
            Transport { ref kind } => kind.cause(),
            Unauthorized { .. } => None,
            UnexpectedContentTypeHeader { .. } => None,
            UnexpectedHttpStatus { .. } => None,
            UriParse { ref cause } => Some(cause),
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use std::error::Error;
        use self::Error::*;
        match *self {
            DatabaseExists { ref response } => write!(f, "{}: {}", self.description(), response),
            Decode { ref kind } => write!(f, "{}: {}", self.description(), kind),
            DocumentConflict { ref response } => write!(f, "{}: {}", self.description(), response),
            Encode { ref cause } => write!(f, "{}: {}", self.description(), cause),
            InternalServerError { ref response } => write!(f, "{}: {}", self.description(), response),
            InvalidDatabaseName { ref response } => write!(f, "{}: {}", self.description(), response),
            InvalidRequest { ref response } => write!(f, "{}: {}", self.description(), response),
            Io { ref cause, .. } => write!(f, "{}: {}", self.description(), cause),
            NoContentTypeHeader { ref expected } => write!(f, "{}: Expected '{}'", self.description(), expected),
            NotFound { ref response } => {
                match *response {
                    Some(ref response) => write!(f, "{}: {}", self.description(), response),
                    None => write!(f, "{}", self.description()),
                }
            }
            ReceiveFromThread { ref cause, .. } => write!(f, "{}: {}", self.description(), cause),
            Transport { ref kind } => write!(f, "{}: {}", self.description(), kind),
            Unauthorized { ref response } => write!(f, "{}: {}", self.description(), response),
            UnexpectedContentTypeHeader { ref expected, ref got } => {
                write!(f,
                       "{}: Expected '{}', got '{}'",
                       self.description(),
                       expected,
                       got)
            }
            UnexpectedHttpStatus { ref got } => write!(f, "{}: Got {}", self.description(), got),
            UriParse { ref cause } => write!(f, "{}: {}", self.description(), cause),
        }
    }
}

/// Response content from the CouchDB server in case of error.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ErrorResponse {
    /// Error string returned by CouchDB Server.
    ///
    /// This is the high-level name of the error—e.g., “file_exists”.
    ///
    pub error: String,

    /// Reason string returned by CouchDB Server.
    ///
    /// This is a low-level description of the error—e.g., “The database could
    /// not be created, the file already exists.”
    ///
    pub reason: String,
}

impl ErrorResponse {
    pub fn from_reader<R>(r: R) -> Result<Self, Error>
        where R: std::io::Read
    {
        serde_json::from_reader::<_, dbtype::ErrorResponse>(r)
            .map_err(|e| Error::Decode { kind: DecodeKind::Serde { cause: e } })
            .map(|x| {
                ErrorResponse {
                    error: x.error,
                    reason: x.reason,
                }
            })
    }
}

impl std::fmt::Display for ErrorResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}: {}", self.error, self.reason)
    }
}

#[derive(Debug)]
pub enum DecodeKind {
    InstanceStartTime {
        got: String,
        cause: std::num::ParseIntError,
    },
    InvalidDocument {
        what: &'static str,
    },
    Serde {
        cause: serde_json::Error,
    },
}

impl DecodeKind {
    fn cause(&self) -> Option<&std::error::Error> {
        use self::DecodeKind::*;
        match *self {
            InstanceStartTime { ref cause, .. } => Some(cause),
            InvalidDocument { .. } => None,
            Serde { ref cause } => Some(cause),
        }
    }
}

impl std::fmt::Display for DecodeKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use self::DecodeKind::*;
        match *self {
            InstanceStartTime { ref got, ref cause } => {
                write!(f,
                       "Could not convert `instance_start_time` field to numeric type: {}: got {}",
                       cause,
                       got)
            }
            InvalidDocument { ref what } => write!(f, "Unexpected document content: {}", what),
            Serde { ref cause } => cause.fmt(f),
        }
    }
}

#[derive(Debug)]
pub enum TransportKind {
    Hyper(hyper::error::Error),
    Io(std::io::Error),
}

impl TransportKind {
    fn cause(&self) -> std::option::Option<&std::error::Error> {
        use self::TransportKind::*;
        match *self {
            Hyper(ref e) => Some(e),
            Io(ref e) => Some(e),
        }
    }
}

impl std::fmt::Display for TransportKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use self::TransportKind::*;
        match *self {
            Hyper(ref e) => e.fmt(f),
            Io(ref e) => e.fmt(f),
        }
    }
}
<commit_msg>Fix doc comments for Error<commit_after>use hyper;
use serde_json;
use std;
use url;

use dbtype;

/// Principal error type.
///
/// The public API guarantees only the non-hidden variants and non-hidden
/// variant fields. Do not match against hidden variants or hidden variant
/// fields.
///
#[derive(Debug)]
pub enum Error {
    /// The database already exists.
    DatabaseExists {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    /// JSON-decoding error.
    Decode {
        #[doc(hidden)]
        kind: DecodeKind,
    },

    /// The client request conflicts with an existing document.
    DocumentConflict {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    /// JSON-encoding error.
    Encode {
        #[doc(hidden)]
        cause: serde_json::error::Error,
    },

    /// An internal server error occurred.
    InternalServerError {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    /// The database name is invalid.
    InvalidDatabaseName {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    /// The client request is invalid.
    InvalidRequest {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    // I/O error with a compile-time description.
    #[doc(hidden)]
    Io {
        description: &'static str,
        cause: std::io::Error,
    },

    // The CouchDB server responded without a Content-Type header.
    #[doc(hidden)]
    NoContentTypeHeader {
        expected: &'static str,
    },

    /// The resource does not exist.
    NotFound {
        /// CouchDB server response.
        ///
        /// In case of a HEAD request, the response value is `None` (because the
        /// server doesn't send response content for HEAD requests). Otherwise,
        /// the response value is `Some`.
        response: Option<ErrorResponse>,
    },

    // Channel-receiver error with a compile-time description and thread-join
    // error.
    #[doc(hidden)]
    ReceiveFromThread {
        description: &'static str,
        cause: std::sync::mpsc::RecvError,
    },

    /// HTTP-transport error.
    Transport {
        #[doc(hidden)]
        kind: TransportKind,
    },

    /// The client is unauthorized to carry out the operation.
    Unauthorized {
        /// CouchDB server response.
        response: ErrorResponse,
    },

    // The CouchDB server responded with a Content-Type header that the client
    // didn't expect.
    #[doc(hidden)]
    UnexpectedContentTypeHeader {
        expected: &'static str,
        got: String,
    },

    // The CouchDB server responded with an HTTP status code that the client
    // didn't expect.
    #[doc(hidden)]
    UnexpectedHttpStatus {
        got: hyper::status::StatusCode,
    },

    /// URI-parse error.
    UriParse {
        #[doc(hidden)]
        cause: url::ParseError,
    },
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            DatabaseExists { .. } => "The database already exists",
            Decode { .. } => "The client failed to decode a JSON response from CouchDB server",
            DocumentConflict { .. } => "The client request conflicts with an existing document",
            Encode { .. } => "The client failed to encode a JSON request to CouchDB server",
            InternalServerError { .. } => "An internal server error occurred",
            InvalidDatabaseName { .. } => "The database name is invalid",
            InvalidRequest { .. } => "The client request is invalid",
            Io { ref description, .. } => description,
            NoContentTypeHeader { .. } => "The CouchDB server responded without a Content-Type header",
            NotFound { .. } => "The resource does not exist",
            ReceiveFromThread { ref description, .. } => description,
            Transport { .. } => "An HTTP transport error occurred",
            Unauthorized { .. } => "The client is unauthorized to carry out the operation",
            UnexpectedContentTypeHeader { .. } => {
                "The CouchDB server responded with a Content-Type header the client did not expect"
            }
            UnexpectedHttpStatus { .. } => {
                "The CouchDB server responded with an HTTP status code the client did not expect"
            }
            UriParse { .. } => "Invalid URI argument",
        }
    }

    fn cause(&self) -> std::option::Option<&std::error::Error> {
        use self::Error::*;
        match *self {
            DatabaseExists { .. } => None,
            Decode { ref kind } => kind.cause(),
            DocumentConflict { .. } => None,
            Encode { ref cause } => Some(cause),
            InternalServerError { .. } => None,
            InvalidDatabaseName { .. } => None,
            InvalidRequest { .. } => None,
            Io { ref cause, .. } => Some(cause),
            NoContentTypeHeader { .. } => None,
            NotFound { .. } => None,
            ReceiveFromThread { ref cause, .. } => Some(cause),
            Transport { ref kind } => kind.cause(),
            Unauthorized { .. } => None,
            UnexpectedContentTypeHeader { .. } => None,
            UnexpectedHttpStatus { .. } => None,
            UriParse { ref cause } => Some(cause),
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use std::error::Error;
        use self::Error::*;
        match *self {
            DatabaseExists { ref response } => write!(f, "{}: {}", self.description(), response),
            Decode { ref kind } => write!(f, "{}: {}", self.description(), kind),
            DocumentConflict { ref response } => write!(f, "{}: {}", self.description(), response),
            Encode { ref cause } => write!(f, "{}: {}", self.description(), cause),
            InternalServerError { ref response } => write!(f, "{}: {}", self.description(), response),
            InvalidDatabaseName { ref response } => write!(f, "{}: {}", self.description(), response),
            InvalidRequest { ref response } => write!(f, "{}: {}", self.description(), response),
            Io { ref cause, .. } => write!(f, "{}: {}", self.description(), cause),
            NoContentTypeHeader { ref expected } => write!(f, "{}: Expected '{}'", self.description(), expected),
            NotFound { ref response } => {
                match *response {
                    Some(ref response) => write!(f, "{}: {}", self.description(), response),
                    None => write!(f, "{}", self.description()),
                }
            }
            ReceiveFromThread { ref cause, .. } => write!(f, "{}: {}", self.description(), cause),
            Transport { ref kind } => write!(f, "{}: {}", self.description(), kind),
            Unauthorized { ref response } => write!(f, "{}: {}", self.description(), response),
            UnexpectedContentTypeHeader { ref expected, ref got } => {
                write!(f,
                       "{}: Expected '{}', got '{}'",
                       self.description(),
                       expected,
                       got)
            }
            UnexpectedHttpStatus { ref got } => write!(f, "{}: Got {}", self.description(), got),
            UriParse { ref cause } => write!(f, "{}: {}", self.description(), cause),
        }
    }
}

/// Response content from the CouchDB server in case of error.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ErrorResponse {
    /// Error string returned by CouchDB Server.
    ///
    /// This is the high-level name of the error—e.g., “file_exists”.
    ///
    pub error: String,

    /// Reason string returned by CouchDB Server.
    ///
    /// This is a low-level description of the error—e.g., “The database could
    /// not be created, the file already exists.”
    ///
    pub reason: String,
}

impl ErrorResponse {
    pub fn from_reader<R>(r: R) -> Result<Self, Error>
        where R: std::io::Read
    {
        serde_json::from_reader::<_, dbtype::ErrorResponse>(r)
            .map_err(|e| Error::Decode { kind: DecodeKind::Serde { cause: e } })
            .map(|x| {
                ErrorResponse {
                    error: x.error,
                    reason: x.reason,
                }
            })
    }
}

impl std::fmt::Display for ErrorResponse {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}: {}", self.error, self.reason)
    }
}

#[derive(Debug)]
pub enum DecodeKind {
    InstanceStartTime {
        got: String,
        cause: std::num::ParseIntError,
    },
    InvalidDocument {
        what: &'static str,
    },
    Serde {
        cause: serde_json::Error,
    },
}

impl DecodeKind {
    fn cause(&self) -> Option<&std::error::Error> {
        use self::DecodeKind::*;
        match *self {
            InstanceStartTime { ref cause, .. } => Some(cause),
            InvalidDocument { .. } => None,
            Serde { ref cause } => Some(cause),
        }
    }
}

impl std::fmt::Display for DecodeKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use self::DecodeKind::*;
        match *self {
            InstanceStartTime { ref got, ref cause } => {
                write!(f,
                       "Could not convert `instance_start_time` field to numeric type: {}: got {}",
                       cause,
                       got)
            }
            InvalidDocument { ref what } => write!(f, "Unexpected document content: {}", what),
            Serde { ref cause } => cause.fmt(f),
        }
    }
}

#[derive(Debug)]
pub enum TransportKind {
    Hyper(hyper::error::Error),
    Io(std::io::Error),
}

impl TransportKind {
    fn cause(&self) -> std::option::Option<&std::error::Error> {
        use self::TransportKind::*;
        match *self {
            Hyper(ref e) => Some(e),
            Io(ref e) => Some(e),
        }
    }
}

impl std::fmt::Display for TransportKind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        use self::TransportKind::*;
        match *self {
            Hyper(ref e) => e.fmt(f),
            Io(ref e) => e.fmt(f),
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(0 <= red && red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // (h, l) >> 127;
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn new(x: u128) -> Fp {
        Fp(x.reduce_once_assert())
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<u128> for Fp {
    #[inline]
    fn from(x: u128) -> Self {
        Fp::new(x)
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        let red = x.0.reduce_once_assert();
        if red == P { 0 } else { red }
    }
}

impl Neg for Fp {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self {
        Fp(P - self.0)
    }
}

impl Add for Fp {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        self + (-other)
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

mod tests {
    use super::*;

    #[test]
    fn neg() {
        assert_eq!(-Fp(0), Fp(0));
        assert_eq!(-Fp(5), Fp(P - 5));
    }

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<commit_msg>Remove useless comparison<commit_after>use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // (h, l) >> 127;
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn new(x: u128) -> Fp {
        Fp(x.reduce_once_assert())
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<u128> for Fp {
    #[inline]
    fn from(x: u128) -> Self {
        Fp::new(x)
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        let red = x.0.reduce_once_assert();
        if red == P { 0 } else { red }
    }
}

impl Neg for Fp {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self {
        Fp(P - self.0)
    }
}

impl Add for Fp {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        self + (-other)
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

mod tests {
    use super::*;

    #[test]
    fn neg() {
        assert_eq!(-Fp(0), Fp(0));
        assert_eq!(-Fp(5), Fp(P - 5));
    }

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<|endoftext|>