use crate::{ErrorPayload, ResponsePayload, RpcSend};
use serde::{ser::SerializeMap, Serialize, Serializer};
use serde_json::value::RawValue;
use std::{borrow::Cow, sync::LazyLock};
#[derive(Debug, Clone)]
pub(crate) struct Response<'a, 'b, T, E> {
pub(crate) id: &'b RawValue,
pub(crate) payload: &'a ResponsePayload<T, E>,
}
static PARSE_ERROR_RESPONSE: LazyLock<Box<RawValue>> = LazyLock::new(|| {
let payload = ResponsePayload::<(), ()>::parse_error();
let resp = Response::<(), ()> {
id: RawValue::NULL,
payload: &payload,
};
serde_json::value::to_raw_value(&resp).expect("parse error response is valid json")
});
static SER_FAILURE_PAYLOAD: ResponsePayload<(), ()> = ResponsePayload(Err(ErrorPayload {
code: -32700,
message: Cow::Borrowed("response serialization error"),
data: None,
}));
impl Response<'_, '_, (), ()> {
pub(crate) fn parse_error() -> Box<RawValue> {
PARSE_ERROR_RESPONSE.clone()
}
pub(crate) fn method_not_found(id: &RawValue) -> Box<RawValue> {
Response::<(), ()> {
id,
payload: &ResponsePayload::method_not_found(),
}
.to_json()
}
pub(crate) fn maybe_method_not_found(id: Option<&RawValue>) -> Option<Box<RawValue>> {
id.map(Self::method_not_found)
}
pub(crate) fn serialization_failure(id: &RawValue) -> Box<RawValue> {
let resp = Response::<(), ()> {
id,
payload: &SER_FAILURE_PAYLOAD,
};
serde_json::value::to_raw_value(&resp).expect("serialization_failure is infallible")
}
pub(crate) fn build_response<T, E>(
id: Option<&RawValue>,
payload: ResponsePayload<T, E>,
) -> Option<Box<RawValue>>
where
T: RpcSend,
E: RpcSend,
{
let id = id?;
let raw = match payload.into_raw() {
Ok(raw) => raw,
Err(err) => {
tracing::debug!(%err, ?id, "failed to serialize response payload");
return Some(Self::serialization_failure(id));
}
};
Some(Response { id, payload: &raw }.to_json())
}
}
impl<'a, 'b, T, E> Response<'a, 'b, T, E>
where
T: Serialize,
E: Serialize,
{
fn to_json(&self) -> Box<RawValue> {
serde_json::value::to_raw_value(self).unwrap_or_else(|err| {
tracing::debug!(%err, id = ?self.id, "failed to serialize response");
Response::serialization_failure(self.id)
})
}
}
impl<T, E> Serialize for Response<'_, '_, T, E>
where
T: Serialize,
E: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("jsonrpc", "2.0")?;
map.serialize_entry("id", &self.id)?;
match &self.payload {
ResponsePayload(Ok(result)) => {
map.serialize_entry("result", result)?;
}
ResponsePayload(Err(error)) => {
map.serialize_entry("error", error)?;
}
}
map.end()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::test_utils::assert_rv_eq;
#[test]
fn ser_failure() {
let id = RawValue::from_string("1".to_string()).unwrap();
let res = Response::<(), ()>::serialization_failure(&id);
assert_rv_eq(
&res,
r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32700,"message":"response serialization error"}}"#,
);
}
}