use crate::ResponsePayload;
use serde::{ser::SerializeMap, Serialize, Serializer};
use serde_json::value::RawValue;
#[derive(Debug, Clone)]
pub(crate) struct Response<'a, 'b, T, E> {
pub(crate) id: &'b RawValue,
pub(crate) payload: &'a ResponsePayload<T, E>,
}
impl Response<'_, '_, (), ()> {
pub(crate) fn parse_error() -> Box<RawValue> {
Response::<(), ()> {
id: RawValue::NULL,
payload: &ResponsePayload::parse_error(),
}
.to_json()
}
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> {
RawValue::from_string(format!(
r#"{{"jsonrpc":"2.0","id":{},"error":{{"code":-32700,"message":"response serialization error"}}}}"#,
id.get()
))
.expect("valid json")
}
}
impl<'a, 'b, T, E> Response<'a, 'b, T, E>
where
T: Serialize,
E: Serialize,
{
pub(crate) fn build_response(
id: Option<&'b RawValue>,
payload: &'a ResponsePayload<T, E>,
) -> Option<Box<RawValue>> {
id.map(move |id| Self { id, payload }.to_json())
}
pub(crate) 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"}}"#,
);
}
}