Skip to content

Commit

Permalink
Mapping of JsonRPCErrorCodes
Browse files Browse the repository at this point in the history
Allow the mapping of error_codes defined in JsonRpc
  • Loading branch information
ErikDeSmedt committed Sep 15, 2023
1 parent de84996 commit eaa1737
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 46 deletions.
4 changes: 2 additions & 2 deletions libs/gl-client/src/lsps/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ impl From<std::io::Error> for LspsError {
}
}

pub fn map_json_rpc_error_code_to_str(code : i64) -> &'static str {
pub fn map_json_rpc_error_code_to_str(code: i64) -> &'static str {
match code {
-32700 => "parsing_error",
-32600 => "invalid_request",
-32601 => "method_not_found",
-32602 => "invalid_params",
-32603 => "internal_error",
-32099..=-32000 => "implementation_defined_server_error",
_ => "unknown_error_code"
_ => "unknown_error_code",
}
}

Expand Down
70 changes: 56 additions & 14 deletions libs/gl-client/src/lsps/json_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use serde::de::DeserializeOwned;
use serde::ser::SerializeMap;
use serde::{Deserialize, Serialize};

use super::error::map_json_rpc_error_code_to_str;

/// Generate a random json_rpc_id string that follows the requirements of LSPS0
///
/// - Should be a String
Expand All @@ -15,7 +17,10 @@ pub fn generate_random_rpc_id() -> String {
}

#[derive(Debug, Serialize, Deserialize)]
pub struct JsonRpcMethod<I, O, E> {
pub struct JsonRpcMethod<I, O, E>
where
E: MapErrorCode,
{
pub method: &'static str,
#[serde(skip_serializing)]
request: std::marker::PhantomData<I>,
Expand All @@ -25,7 +30,10 @@ pub struct JsonRpcMethod<I, O, E> {
error_type: std::marker::PhantomData<E>,
}

impl<I, O, E> JsonRpcMethod<I, O, E> {
impl<I, O, E> JsonRpcMethod<I, O, E>
where
E: MapErrorCode,
{
pub const fn new(method: &'static str) -> Self {
return Self {
method: method,
Expand All @@ -49,13 +57,19 @@ impl<I, O, E> JsonRpcMethod<I, O, E> {
}
}

impl<O, E> JsonRpcMethod<NoParams, O, E> {
impl<O, E> JsonRpcMethod<NoParams, O, E>
where
E: MapErrorCode,
{
pub fn create_request_no_params(&self, json_rpc_id: String) -> JsonRpcRequest<NoParams> {
self.create_request(NoParams::default(), json_rpc_id)
}
}

impl<'a, I, O, E> std::convert::From<&JsonRpcMethod<I, O, E>> for String {
impl<'a, I, O, E> std::convert::From<&JsonRpcMethod<I, O, E>> for String
where
E: MapErrorCode,
{
fn from(value: &JsonRpcMethod<I, O, E>) -> Self {
return value.method.clone().into();
}
Expand All @@ -64,7 +78,7 @@ impl<'a, I, O, E> std::convert::From<&JsonRpcMethod<I, O, E>> for String {
impl<'de, I, O, E> JsonRpcMethod<I, O, E>
where
O: Deserialize<'de>,
E: Deserialize<'de>,
E: Deserialize<'de> + MapErrorCode,
{
pub fn parse_json_response_str(
&self,
Expand All @@ -77,7 +91,7 @@ where
impl<I, O, E> JsonRpcMethod<I, O, E>
where
O: DeserializeOwned,
E: DeserializeOwned,
E: DeserializeOwned + MapErrorCode,
{
pub fn parse_json_response_value(
&self,
Expand Down Expand Up @@ -119,7 +133,10 @@ impl Serialize for NoParams {
}

impl<I> JsonRpcRequest<I> {
pub fn new<O, E>(method: JsonRpcMethod<I, O, E>, params: I) -> Self {
pub fn new<O, E>(method: JsonRpcMethod<I, O, E>, params: I) -> Self
where
E: MapErrorCode,
{
return Self {
jsonrpc: String::from("2.0"),
id: generate_random_rpc_id(),
Expand All @@ -130,7 +147,10 @@ impl<I> JsonRpcRequest<I> {
}

impl JsonRpcRequest<NoParams> {
pub fn new_no_params<O, E>(method: JsonRpcMethod<NoParams, O, E>) -> Self {
pub fn new_no_params<O, E>(method: JsonRpcMethod<NoParams, O, E>) -> Self
where
E: MapErrorCode,
{
return Self {
jsonrpc: String::from("2.0"),
id: generate_random_rpc_id(),
Expand Down Expand Up @@ -168,6 +188,28 @@ pub struct ErrorData<E> {
pub data: Option<E>,
}

impl<E> ErrorData<E>
where
E: MapErrorCode,
{
pub fn code_str(&self) -> &str {
return E::get_code_str(self.code);
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DefaultError;

pub trait MapErrorCode {
fn get_code_str(code: i64) -> &'static str;
}

impl MapErrorCode for DefaultError {
fn get_code_str(code: i64) -> &'static str {
map_json_rpc_error_code_to_str(code)
}
}

#[cfg(test)]
mod test {

Expand Down Expand Up @@ -249,7 +291,7 @@ mod test {

#[test]
fn create_rpc_request_from_call() {
let rpc_method = JsonRpcMethod::<NoParams, (), ()>::new("test.method");
let rpc_method = JsonRpcMethod::<NoParams, (), DefaultError>::new("test.method");
let json_rpc_id = generate_random_rpc_id();
let rpc_request = rpc_method.create_request_no_params(json_rpc_id);

Expand All @@ -260,7 +302,7 @@ mod test {

#[test]
fn parse_rpc_response_success_from_call() {
let rpc_method = JsonRpcMethod::<NoParams, String, ()>::new("test.return_string");
let rpc_method = JsonRpcMethod::<NoParams, String, DefaultError>::new("test.return_string");

let json_value = serde_json::json!({
"jsonrpc" : "2.0",
Expand All @@ -284,8 +326,7 @@ mod test {

#[test]
fn parse_rpc_response_failure_from_call() {
let rpc_method: JsonRpcMethod<NoParams, String, ()> =
JsonRpcMethod::<NoParams, String, ()>::new("test.return_string");
let rpc_method = JsonRpcMethod::<NoParams, String, DefaultError>::new("test.return_string");

let json_value = serde_json::json!({
"jsonrpc" : "2.0",
Expand All @@ -302,9 +343,10 @@ mod test {
assert_eq!(err.jsonrpc, "2.0");

assert_eq!(err.error.code, -32700);
assert_eq!(err.error.message, "Failed to parse response");
assert_eq!(err.error.code_str(), "parsing_error");

assert_eq!(err.id, "request_id")
assert_eq!(err.error.message, "Failed to parse response");
assert_eq!(err.id, "request_id");
}
JsonRpcResponse::Ok(_ok) => {
panic!("Failure deserialized as Ok")
Expand Down
24 changes: 13 additions & 11 deletions libs/gl-client/src/lsps/json_rpc_erased.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

use crate::lsps::json_rpc::{
ErrorData, JsonRpcMethod, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseFailure,
JsonRpcResponseSuccess,
JsonRpcResponseSuccess, MapErrorCode,
};
use serde::Serialize;

Expand Down Expand Up @@ -54,7 +54,7 @@ impl<I, O, E> JsonRpcMethodErased for JsonRpcMethod<I, O, E>
where
I: serde::de::DeserializeOwned + Serialize,
O: serde::de::DeserializeOwned + Serialize,
E: serde::de::DeserializeOwned + Serialize,
E: serde::de::DeserializeOwned + Serialize + MapErrorCode,
{
fn name(&self) -> &str {
&self.method
Expand Down Expand Up @@ -95,7 +95,7 @@ impl<I, O, E> JsonRpcMethod<I, O, E>
where
I: serde::de::DeserializeOwned + Serialize + 'static,
O: serde::de::DeserializeOwned + Serialize + 'static,
E: serde::de::DeserializeOwned + Serialize + 'static,
E: serde::de::DeserializeOwned + Serialize + 'static + MapErrorCode,
{
pub fn erase_box(self) -> Box<dyn JsonRpcMethodErased> {
return Box::new(self);
Expand Down Expand Up @@ -143,7 +143,7 @@ pub trait JsonRpcMethodUnerased<'a, I, O, E> {
impl<'a, I, O, E> JsonRpcMethodUnerased<'a, I, O, E> for JsonRpcMethod<I, O, E>
where
O: serde::de::DeserializeOwned,
E: serde::de::DeserializeOwned,
E: serde::de::DeserializeOwned + MapErrorCode,
{
fn name(&self) -> &str {
JsonRpcMethod::name(self)
Expand Down Expand Up @@ -292,7 +292,7 @@ where
#[cfg(test)]
mod test {
use super::*;
use crate::lsps::json_rpc::{generate_random_rpc_id, JsonRpcMethod};
use crate::lsps::json_rpc::{generate_random_rpc_id, DefaultError, JsonRpcMethod};

#[derive(Serialize, serde::Deserialize)]
struct TestRequestStruct {
Expand All @@ -306,7 +306,7 @@ mod test {

#[test]
fn create_rpc_request_from_method_erased() {
let rpc_method = JsonRpcMethod::<TestRequestStruct, (), ()>::new("test.method");
let rpc_method = JsonRpcMethod::<TestRequestStruct, (), DefaultError>::new("test.method");
let rpc_method_erased = rpc_method.erase_box();

// This rpc-request should work becasue the parameters match the schema
Expand All @@ -322,7 +322,7 @@ mod test {

#[test]
fn create_rpc_request_from_method_erased_checks_types() {
let rpc_method = JsonRpcMethod::<TestRequestStruct, (), ()>::new("test.method");
let rpc_method = JsonRpcMethod::<TestRequestStruct, (), DefaultError>::new("test.method");
let rpc_method_erased = rpc_method.erase_box();

// This rpc-request should fail because the parameters do not match the schema
Expand All @@ -335,8 +335,9 @@ mod test {

#[test]
fn parse_rpc_request_from_method_erased() {
let rpc_method =
JsonRpcMethod::<TestRequestStruct, TestResponseStruct, ()>::new("test.method");
let rpc_method = JsonRpcMethod::<TestRequestStruct, TestResponseStruct, DefaultError>::new(
"test.method",
);
let rpc_method_erased = rpc_method.erase_box();

let json_value = serde_json::json!({
Expand All @@ -352,8 +353,9 @@ mod test {

#[test]
fn parse_rpc_request_from_method_erased_fails() {
let rpc_method =
JsonRpcMethod::<TestRequestStruct, TestResponseStruct, ()>::new("test.method");
let rpc_method = JsonRpcMethod::<TestRequestStruct, TestResponseStruct, DefaultError>::new(
"test.method",
);
let rpc_method_erased = rpc_method.erase_box();

let json_value = serde_json::json!({
Expand Down
Loading

0 comments on commit eaa1737

Please sign in to comment.