1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::convert::TryFrom;

use serde::{Deserialize, Serialize};
use serde_json::Value;

/// An RPC error, as defined in the RPC specification.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Error {
    code: i32,
    message: String,
    data: Option<Value>,
}

/// An RPC request ID. Can be a string (`Str`) or an integer (`Int`).
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
#[serde(untagged)]
pub enum RequestId {
    Str(String),
    Int(i32),
}

impl From<String> for RequestId {
    fn from(str: String) -> Self {
        RequestId::Str(str)
    }
}

impl From<i32> for RequestId {
    fn from(i: i32) -> Self {
        RequestId::Int(i)
    }
}

/// An RPC message. One of [`Request`, `Response`, `Notification`].
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum Message {
    Request {
        jsonrpc: String,
        id: RequestId,
        method: String,
        params: Option<Value>,
    },
    Response {
        jsonrpc: String,
        id: RequestId,
        result: Option<Value>,
        error: Option<Error>,
    },
    Notification {
        jsonrpc: String,
        method: String,
        params: Option<Value>,
    },
}

impl Message {
    pub fn request(id: RequestId, method: String, params: Option<Value>) -> Self {
        Message::Request {
            jsonrpc: String::from("2.0"),
            id,
            method,
            params,
        }
    }

    pub fn response(id: RequestId, result: Option<Value>, error: Option<Error>) -> Self {
        Message::Response {
            jsonrpc: String::from("2.0"),
            id,
            result,
            error,
        }
    }

    pub fn notification(method: String, params: Option<Value>) -> Self {
        Message::Notification {
            jsonrpc: String::from("2.0"),
            method,
            params,
        }
    }
}

/// A struct that contains the same data as `Message::Response`.
/// Used to save redundant `match`es against a `Message` that is
/// known to be a `Message::Response`.
#[derive(Debug, Clone)]
pub struct Response {
    pub id: RequestId,
    pub result: Option<Value>,
    pub error: Option<Error>,
}

impl TryFrom<Message> for Response {
    type Error = ();

    fn try_from(value: Message) -> Result<Self, Self::Error> {
        match value {
            Message::Response {
                id, result, error, ..
            } => Ok(Self { id, result, error }),
            _ => Err(()),
        }
    }
}

impl From<Response> for Message {
    fn from(value: Response) -> Self {
        Self::Response {
            jsonrpc: "2.0".into(),
            id: value.id,
            result: value.result,
            error: value.error,
        }
    }
}