use crate::RpcSend;
use serde::Serialize;
use serde_json::value::{to_raw_value, RawValue};
use std::borrow::Cow;
use std::fmt;
const INTERNAL_ERROR: Cow<'_, str> = Cow::Borrowed("Internal error");
#[derive(Clone, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct ResponsePayload<Payload, ErrData>(pub Result<Payload, ErrorPayload<ErrData>>);
impl<T, E> From<Result<T, E>> for ResponsePayload<T, E>
where
E: RpcSend,
{
fn from(res: Result<T, E>) -> Self {
match res {
Ok(payload) => Self(Ok(payload)),
Err(err) => Self(Err(ErrorPayload::internal_error_with_obj(err))),
}
}
}
impl<Payload, ErrData> ResponsePayload<Payload, ErrData> {
pub const fn parse_error() -> Self {
Self(Err(ErrorPayload::parse_error()))
}
pub const fn invalid_request() -> Self {
Self(Err(ErrorPayload::invalid_request()))
}
pub const fn method_not_found() -> Self {
Self(Err(ErrorPayload::method_not_found()))
}
pub const fn invalid_params() -> Self {
Self(Err(ErrorPayload::invalid_params()))
}
pub const fn internal_error() -> Self {
Self(Err(ErrorPayload::internal_error()))
}
pub const fn internal_error_message(message: Cow<'static, str>) -> Self {
Self(Err(ErrorPayload::internal_error_message(message)))
}
pub const fn internal_error_with_obj(data: ErrData) -> Self
where
ErrData: RpcSend,
{
Self(Err(ErrorPayload::internal_error_with_obj(data)))
}
pub const fn internal_error_with_message_and_obj(
message: Cow<'static, str>,
data: ErrData,
) -> Self
where
ErrData: RpcSend,
{
Self(Err(ErrorPayload::internal_error_with_message_and_obj(
message, data,
)))
}
pub const fn as_success(&self) -> Option<&Payload> {
match self {
Self(Ok(payload)) => Some(payload),
_ => None,
}
}
pub const fn as_error(&self) -> Option<&ErrorPayload<ErrData>> {
match self {
Self(Err(payload)) => Some(payload),
_ => None,
}
}
pub const fn is_success(&self) -> bool {
matches!(self, Self(Ok(_)))
}
pub const fn is_error(&self) -> bool {
matches!(self, Self(Err(_)))
}
pub fn convert_internal_error_msg<T>(res: Result<Payload, T>) -> Self
where
T: Into<Cow<'static, str>>,
{
match res {
Ok(payload) => Self(Ok(payload)),
Err(err) => Self(Err(ErrorPayload::internal_error_message(err.into()))),
}
}
}
#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
pub struct ErrorPayload<ErrData = Box<RawValue>> {
pub code: i64,
pub message: Cow<'static, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<ErrData>,
}
impl<E> ErrorPayload<E> {
pub const fn parse_error() -> Self {
Self {
code: -32700,
message: Cow::Borrowed("Parse error"),
data: None,
}
}
pub const fn invalid_request() -> Self {
Self {
code: -32600,
message: Cow::Borrowed("Invalid Request"),
data: None,
}
}
pub const fn method_not_found() -> Self {
Self {
code: -32601,
message: Cow::Borrowed("Method not found"),
data: None,
}
}
pub const fn invalid_params() -> Self {
Self {
code: -32602,
message: Cow::Borrowed("Invalid params"),
data: None,
}
}
pub const fn internal_error() -> Self {
Self {
code: -32603,
message: INTERNAL_ERROR,
data: None,
}
}
pub const fn internal_error_message(message: Cow<'static, str>) -> Self {
Self {
code: -32603,
message,
data: None,
}
}
pub const fn internal_error_with_obj(data: E) -> Self
where
E: RpcSend,
{
Self {
code: -32603,
message: INTERNAL_ERROR,
data: Some(data),
}
}
pub const fn internal_error_with_message_and_obj(message: Cow<'static, str>, data: E) -> Self
where
E: RpcSend,
{
Self {
code: -32603,
message,
data: Some(data),
}
}
}
impl<T> From<T> for ErrorPayload<T>
where
T: std::error::Error + RpcSend,
{
fn from(value: T) -> Self {
Self {
code: -32603,
message: INTERNAL_ERROR,
data: Some(value),
}
}
}
impl<E> ErrorPayload<E>
where
E: RpcSend,
{
#[deprecated(note = "use `into_raw` instead")]
pub fn serialize_payload(&self) -> serde_json::Result<ErrorPayload>
where
E: Serialize,
{
Ok(ErrorPayload {
code: self.code,
message: self.message.clone(),
data: match self.data.as_ref() {
Some(data) => Some(to_raw_value(data)?),
None => None,
},
})
}
pub fn into_raw(self) -> serde_json::Result<ErrorPayload> {
Ok(ErrorPayload {
code: self.code,
message: self.message,
data: self.data.map(|d| d.into_raw_value()).transpose()?,
})
}
}
impl<T, E> ResponsePayload<T, E>
where
T: RpcSend,
E: RpcSend,
{
pub(crate) fn into_raw(
self,
) -> serde_json::Result<ResponsePayload<Box<RawValue>, Box<RawValue>>> {
match self.0 {
Ok(payload) => Ok(ResponsePayload(Ok(payload.into_raw_value()?))),
Err(err) => Ok(ResponsePayload(Err(err.into_raw()?))),
}
}
}
impl<ErrData: fmt::Display> fmt::Display for ErrorPayload<ErrData> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"error code {}: {}{}",
self.code,
self.message,
self.data
.as_ref()
.map(|data| format!(", data: {}", data))
.unwrap_or_default()
)
}
}