use std::{
    borrow::Cow,
    convert::Infallible,
    io,
};
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum ReadErrorKind {
    #[error("received a buffer with more than usize::MAX elements: {0}")]
    BufSize(#[from] std::num::TryFromIntError),
    #[error("{0}")]
    Custom(String),
    #[error("reached end of stream")]
    EndOfStream,
    #[error("received an infinite or NaN number")]
    FloatNotFinite,
    #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))]
    #[error("unexpected type of WebSocket message")]
    MessageKind(tungstenite::Message),
    #[error("attempted to read an empty type")]
    ReadNever,
    #[error("{0:?}")] TryReserve(fallible_collections::TryReserveError),
    #[error("unknown enum variant: {0}")]
    UnknownVariant8(u8),
    #[error("unknown enum variant: {0}")]
    UnknownVariant16(u16),
    #[error("unknown enum variant: {0}")]
    UnknownVariant32(u32),
    #[error("unknown enum variant: {0}")]
    UnknownVariant64(u64),
    #[error("unknown enum variant: {0}")]
    UnknownVariant128(u128),
    #[error(transparent)] Io(#[from] io::Error),
    #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))]
    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))))]
    #[error(transparent)] Tungstenite(#[from] tungstenite::Error),
    #[error(transparent)] Utf8(#[from] std::string::FromUtf8Error),
    #[cfg(feature = "warp")]
    #[cfg_attr(docsrs, doc(cfg(feature = "warp")))]
    #[error(transparent)] Warp(#[from] warp::Error),
}
impl From<Infallible> for ReadErrorKind {
    fn from(never: Infallible) -> Self {
        match never {}
    }
}
impl From<String> for ReadErrorKind {
    fn from(s: String) -> Self {
        Self::Custom(s)
    }
}
impl<'a> From<&'a str> for ReadErrorKind {
    fn from(s: &str) -> Self {
        Self::Custom(s.to_owned())
    }
}
impl<'a> From<Cow<'a, str>> for ReadErrorKind {
    fn from(s: Cow<'a, str>) -> Self {
        Self::Custom(s.into_owned())
    }
}
impl From<fallible_collections::TryReserveError> for ReadErrorKind {
    fn from(e: fallible_collections::TryReserveError) -> Self {
        Self::TryReserve(e)
    }
}
impl From<ReadErrorKind> for io::Error {
    fn from(e: ReadErrorKind) -> Self {
        match e {
            ReadErrorKind::BufSize(e) => io::Error::new(io::ErrorKind::InvalidData, e),
            ReadErrorKind::Io(e) => e,
            #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))] ReadErrorKind::Tungstenite(e) => io::Error::new(io::ErrorKind::Other, e),
            ReadErrorKind::Utf8(e) => io::Error::new(io::ErrorKind::InvalidData, e),
            #[cfg(feature = "warp")] ReadErrorKind::Warp(e) => io::Error::new(io::ErrorKind::Other, e),
            ReadErrorKind::EndOfStream => io::Error::new(io::ErrorKind::UnexpectedEof, e),
            ReadErrorKind::FloatNotFinite |
            ReadErrorKind::UnknownVariant8(_) |
            ReadErrorKind::UnknownVariant16(_) |
            ReadErrorKind::UnknownVariant32(_) |
            ReadErrorKind::UnknownVariant64(_) |
            ReadErrorKind::UnknownVariant128(_) => io::Error::new(io::ErrorKind::InvalidData, e),
            #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))] ReadErrorKind::MessageKind(_) => io::Error::new(io::ErrorKind::InvalidData, e),
            ReadErrorKind::ReadNever => io::Error::new(io::ErrorKind::InvalidInput, e),
            ReadErrorKind::TryReserve(_) => io::Error::new(io::ErrorKind::OutOfMemory, e),
            ReadErrorKind::Custom(_) => io::Error::new(io::ErrorKind::Other, e),
        }
    }
}
impl From<ReadError> for io::Error {
    fn from(ReadError { kind, .. }: ReadError) -> Self {
        kind.into()
    }
}
#[derive(Debug, thiserror::Error)]
#[error("{kind}")]
pub struct ReadError {
    pub context: ErrorContext,
    pub kind: ReadErrorKind,
}
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum WriteErrorKind {
    #[error("tried to send a buffer with more than u64::MAX elements: {0}")]
    BufSize(#[from] std::num::TryFromIntError),
    #[error("{0}")]
    Custom(String),
    #[error(transparent)] Io(#[from] io::Error),
    #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))]
    #[cfg_attr(docsrs, doc(cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))))]
    #[error(transparent)] Tungstenite(#[from] tungstenite::Error),
    #[cfg(feature = "warp")]
    #[cfg_attr(docsrs, doc(cfg(feature = "warp")))]
    #[error(transparent)] Warp(#[from] warp::Error),
}
impl From<Infallible> for WriteErrorKind {
    fn from(never: Infallible) -> Self {
        match never {}
    }
}
impl From<String> for WriteErrorKind {
    fn from(s: String) -> Self {
        Self::Custom(s)
    }
}
impl<'a> From<&'a str> for WriteErrorKind {
    fn from(s: &str) -> Self {
        Self::Custom(s.to_owned())
    }
}
impl<'a> From<Cow<'a, str>> for WriteErrorKind {
    fn from(s: Cow<'a, str>) -> Self {
        Self::Custom(s.into_owned())
    }
}
impl From<WriteErrorKind> for io::Error {
    fn from(e: WriteErrorKind) -> Self {
        match e {
            WriteErrorKind::BufSize(e) => io::Error::new(io::ErrorKind::InvalidData, e),
            WriteErrorKind::Io(e) => e,
            #[cfg(any(feature = "tokio-tungstenite", feature = "tungstenite"))] WriteErrorKind::Tungstenite(e) => io::Error::new(io::ErrorKind::Other, e),
            #[cfg(feature = "warp")] WriteErrorKind::Warp(e) => io::Error::new(io::ErrorKind::Other, e),
            WriteErrorKind::Custom(_) => io::Error::new(io::ErrorKind::Other, e),
        }
    }
}
impl From<WriteError> for io::Error {
    fn from(WriteError { kind, .. }: WriteError) -> Self {
        kind.into()
    }
}
#[derive(Debug, thiserror::Error)]
#[error("{kind}")]
pub struct WriteError {
    pub context: ErrorContext,
    pub kind: WriteErrorKind,
}
#[derive(Debug)]
pub enum ErrorContext {
    Custom(String),
    BuiltIn {
        for_type: &'static str,
    },
    WebSocket {
        source: Box<Self>,
    },
    DefaultImpl,
    Derived {
        for_type: &'static str,
    },
    EnumDiscrim {
        source: Box<Self>,
    },
    UnnamedField {
        idx: usize,
        source: Box<Self>,
    },
    NamedField {
        name: &'static str,
        source: Box<Self>,
    },
    FromStr,
    AsString {
        source: Box<Self>,
    },
    TryInto,
    Via {
        source: Box<Self>,
    },
    Bitflags {
        source: Box<Self>,
    },
}