use std::collections::BTreeMap;
use std::fmt;
use serde_json::Value;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
kind: ErrorKind,
code: Option<String>,
message: String,
details: Option<BTreeMap<String, Value>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
Authorization,
Config,
Decode,
Io,
Protocol,
Receipt,
Rpc,
Timeout,
Transport,
Wallet,
Other,
}
impl Error {
pub fn new(message: impl Into<String>) -> Self {
Self::with_kind(ErrorKind::Other, message)
}
pub fn with_kind(kind: ErrorKind, message: impl Into<String>) -> Self {
Self {
kind,
code: None,
message: message.into(),
details: None,
}
}
pub(crate) fn with_code(
kind: ErrorKind,
code: impl Into<String>,
message: impl Into<String>,
) -> Self {
Self {
kind,
code: Some(code.into()),
message: message.into(),
details: None,
}
}
pub(crate) fn with_code_and_details(
kind: ErrorKind,
code: impl Into<String>,
message: impl Into<String>,
details: impl IntoIterator<Item = (impl Into<String>, Value)>,
) -> Self {
Self {
kind,
code: Some(code.into()),
message: message.into(),
details: Some(
details
.into_iter()
.map(|(key, value)| (key.into(), value))
.collect(),
),
}
}
pub(crate) fn with_context(mut self, context: impl AsRef<str>) -> Self {
self.message = format!("{}; {}", self.message, context.as_ref());
self
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn code(&self) -> Option<&str> {
self.code.as_deref()
}
pub fn details(&self) -> Option<&BTreeMap<String, Value>> {
self.details.as_ref()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for Error {}
impl From<crate::protocol::error::Error> for Error {
fn from(error: crate::protocol::error::Error) -> Self {
Self::with_kind(ErrorKind::Protocol, error.to_string())
}
}
impl From<base64::DecodeError> for Error {
fn from(error: base64::DecodeError) -> Self {
Self::with_kind(ErrorKind::Decode, error.to_string())
}
}
impl From<hex::FromHexError> for Error {
fn from(error: hex::FromHexError) -> Self {
Self::with_kind(ErrorKind::Decode, error.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
Self::with_kind(ErrorKind::Decode, error.to_string())
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Self::with_kind(ErrorKind::Io, error.to_string())
}
}
#[cfg(feature = "http")]
impl From<ureq::Error> for Error {
fn from(error: ureq::Error) -> Self {
Self::with_kind(ErrorKind::Transport, error.to_string())
}
}