use crate::{addr::AddrParseError, group::GroupParseError};
use libzmq_sys as sys;
use thiserror::Error;
use std::{convert::Infallible, ffi, fmt, io, str};
pub struct Error<T = ()> {
kind: ErrorKind,
content: Option<T>,
}
impl<T> Error<T> {
pub(crate) fn new(kind: ErrorKind) -> Self {
Self {
kind,
content: None,
}
}
pub(crate) fn with_content(kind: ErrorKind, content: T) -> Self {
Self {
kind,
content: Some(content),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
#[deprecated(since = "0.2.1", note = "please use `get` instead")]
pub fn content(&self) -> Option<&T> {
self.content.as_ref()
}
pub fn get(&self) -> Option<&T> {
self.content.as_ref()
}
#[deprecated(since = "0.2.1", note = "please use `take` instead")]
pub fn take_content(&mut self) -> Option<T> {
self.content.take()
}
pub fn take(&mut self) -> Option<T> {
self.content.take()
}
pub fn cast<I>(self) -> Error<I> {
Error {
kind: self.kind,
content: None,
}
}
}
impl<T> std::error::Error for Error<T> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.kind.source()
}
}
impl<T> fmt::Debug for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Error").field("kind", &self.kind).finish()
}
}
impl<T> fmt::Display for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.kind, f)
}
}
impl<T> From<GroupParseError> for Error<T> {
fn from(_error: GroupParseError) -> Self {
Error::new(ErrorKind::InvalidInput("unable to parse group"))
}
}
impl<T> From<AddrParseError> for Error<T> {
fn from(error: AddrParseError) -> Self {
Error::new(ErrorKind::InvalidInput(error.msg()))
}
}
impl<T> From<Infallible> for Error<T> {
fn from(_error: Infallible) -> Self {
unreachable!()
}
}
impl<T> From<Error<T>> for io::Error {
fn from(err: Error<T>) -> io::Error {
use ErrorKind::*;
match err.kind() {
WouldBlock => io::Error::from(io::ErrorKind::WouldBlock),
HostUnreachable => {
io::Error::new(io::ErrorKind::BrokenPipe, "host unreachable")
}
InvalidCtx => {
io::Error::new(io::ErrorKind::Other, "context terminated")
}
Interrupted => io::Error::from(io::ErrorKind::Interrupted),
AddrInUse => io::Error::from(io::ErrorKind::AddrInUse),
AddrNotAvailable => {
io::Error::from(io::ErrorKind::AddrNotAvailable)
}
NotFound(msg) => io::Error::new(io::ErrorKind::NotFound, msg),
SocketLimit => {
io::Error::new(io::ErrorKind::Other, "socket limit reached")
}
InvalidInput(msg) => {
io::Error::new(io::ErrorKind::InvalidInput, msg)
}
}
}
}
#[derive(Debug, Error, Copy, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
#[error("operation would block")]
WouldBlock,
#[error("host unreachable")]
HostUnreachable,
#[error("context invalidated")]
InvalidCtx,
#[error("interrupted by signal")]
Interrupted,
#[error("addr in use")]
AddrInUse,
#[error("addr not available")]
AddrNotAvailable,
#[error("not found: {}", _0)]
NotFound(&'static str),
#[error("open socket limit was reached")]
SocketLimit,
#[error("invalid input: {}", _0)]
InvalidInput(&'static str),
}
pub(crate) fn msg_from_errno(x: i32) -> String {
unsafe {
let s = sys::zmq_strerror(x);
format!(
"unknown error [{}]: {}",
x,
str::from_utf8(ffi::CStr::from_ptr(s).to_bytes()).unwrap()
)
}
}