use std::fmt;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value;
use crate::{
error::{Error, ErrorCode},
id::Id,
v2::version::Version,
};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Success<T = Value> {
pub jsonrpc: Version,
pub result: T,
pub id: Id,
}
impl<T: Serialize> fmt::Display for Success<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let json = serde_json::to_string(self).expect("`Success` is serializable");
write!(f, "{}", json)
}
}
impl<T: Serialize + DeserializeOwned> Success<T> {
pub fn new(result: T, id: Id) -> Self {
Self {
jsonrpc: Version::V2_0,
result,
id,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Failure {
pub jsonrpc: Version,
pub error: Error,
pub id: Option<Id>,
}
impl fmt::Display for Failure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let json = serde_json::to_string(self).expect("`Failure` is serializable");
write!(f, "{}", json)
}
}
impl Failure {
pub fn new(error: Error, id: Option<Id>) -> Self {
Self {
jsonrpc: Version::V2_0,
error,
id,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(untagged)]
pub enum Output<T = Value> {
Success(Success<T>),
Failure(Failure),
}
impl<T: Serialize> fmt::Display for Output<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let json = serde_json::to_string(self).expect("`Output` is serializable");
write!(f, "{}", json)
}
}
impl<T: Serialize + DeserializeOwned> Output<T> {
pub fn success(result: T, id: Id) -> Self {
Self::Success(Success::new(result, id))
}
pub fn failure(error: Error, id: Option<Id>) -> Self {
Self::Failure(Failure::new(error, id))
}
pub fn invalid_request(id: Option<Id>) -> Self {
Self::Failure(Failure::new(Error::new(ErrorCode::InvalidRequest), id))
}
pub fn version(&self) -> Version {
match self {
Self::Success(s) => s.jsonrpc,
Self::Failure(f) => f.jsonrpc,
}
}
pub fn id(&self) -> Option<Id> {
match self {
Self::Success(s) => Some(s.id.clone()),
Self::Failure(f) => f.id.clone(),
}
}
}
impl<T: Serialize + DeserializeOwned> From<Output<T>> for Result<T, Error> {
fn from(output: Output<T>) -> Result<T, Error> {
match output {
Output::Success(s) => Ok(s.result),
Output::Failure(f) => Err(f.error),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(untagged)]
pub enum Response<T = Value> {
Single(Output<T>),
Batch(Vec<Output<T>>),
}
impl<T: Serialize> fmt::Display for Response<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let json = serde_json::to_string(self).expect("`Response` is serializable");
write!(f, "{}", json)
}
}
impl<T> From<Success<T>> for Response<T> {
fn from(success: Success<T>) -> Self {
Response::Single(Output::<T>::Success(success))
}
}
impl<T> From<Failure> for Response<T> {
fn from(failure: Failure) -> Self {
Response::Single(Output::<T>::Failure(failure))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn success_response_cases() -> Vec<(Success, &'static str)> {
vec![(
Success {
jsonrpc: Version::V2_0,
result: Value::Bool(true),
id: Id::Num(1),
},
r#"{"jsonrpc":"2.0","result":true,"id":1}"#,
)]
}
fn failure_response_cases() -> Vec<(Failure, &'static str)> {
vec![
(
Failure {
jsonrpc: Version::V2_0,
error: Error::parse_error(),
id: Some(Id::Num(1)),
},
r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":1}"#,
),
(
Failure {
jsonrpc: Version::V2_0,
error: Error::parse_error(),
id: None,
},
r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#,
),
]
}
#[test]
fn success_response_serialization() {
for (success_response, expect) in success_response_cases() {
let ser = serde_json::to_string(&success_response).unwrap();
assert_eq!(ser, expect);
let de = serde_json::from_str::<Success>(expect).unwrap();
assert_eq!(de, success_response);
}
}
#[test]
fn failure_response_serialization() {
for (failure_response, expect) in failure_response_cases() {
let ser = serde_json::to_string(&failure_response).unwrap();
assert_eq!(ser, expect);
let de = serde_json::from_str::<Failure>(expect).unwrap();
assert_eq!(de, failure_response);
}
}
#[test]
fn response_output_serialization() {
for (success_response, expect) in success_response_cases() {
let response_output = Output::Success(success_response);
assert_eq!(serde_json::to_string(&response_output).unwrap(), expect);
assert_eq!(serde_json::from_str::<Output>(expect).unwrap(), response_output);
}
for (failure_response, expect) in failure_response_cases() {
let response_output = Output::Failure(failure_response);
assert_eq!(serde_json::to_string(&response_output).unwrap(), expect);
assert_eq!(serde_json::from_str::<Output>(expect).unwrap(), response_output);
}
}
#[test]
fn response_serialization() {
for (success_resp, expect) in success_response_cases() {
let success_response = Response::Single(Output::Success(success_resp.clone()));
assert_eq!(serde_json::to_string(&success_response).unwrap(), expect);
assert_eq!(serde_json::from_str::<Response>(expect).unwrap(), success_response);
}
for (failure_resp, expect) in failure_response_cases() {
let failure_response = Response::Single(Output::Failure(failure_resp.clone()));
assert_eq!(serde_json::to_string(&failure_response).unwrap(), expect);
assert_eq!(serde_json::from_str::<Response>(expect).unwrap(), failure_response);
}
for ((success_resp, success_expect), (failure_resp, failure_expect)) in
success_response_cases().into_iter().zip(failure_response_cases())
{
let batch_response = Response::Batch(vec![Output::Success(success_resp), Output::Failure(failure_resp)]);
let batch_expect = format!("[{},{}]", success_expect, failure_expect);
assert_eq!(serde_json::to_string(&batch_response).unwrap(), batch_expect);
assert_eq!(serde_json::from_str::<Response>(&batch_expect).unwrap(), batch_response);
}
}
#[test]
fn invalid_response() {
let cases = vec![
r#"{"jsonrpc":"2.0","result":true,"id":1,"unknown":[]}"#,
r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":1,"unknown":[]}"#,
r#"{"jsonrpc":"2.0","result":true,"error":{"code": -32700,"message": "Parse error"},"id":1}"#,
r#"{"jsonrpc":"2.0","id":1}"#,
r#"{"jsonrpc":"2.0","unknown":[]}"#,
];
for case in cases {
let response = serde_json::from_str::<Response>(case);
assert!(response.is_err());
}
}
#[test]
fn valid_response() {
let cases = vec![
r#"{"jsonrpc":"2.0","result":true,"id":1}"#,
r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":1}"#,
r#"{"jsonrpc":"2.0","error":{"code": -32700,"message": "Parse error"},"id":null}"#,
];
for case in cases {
let response = serde_json::from_str::<Response>(case);
assert!(response.is_ok());
}
}
}