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
118
119
120
121
122
use crate::error::ParamsError as Error;
use crate::JsonValue;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, Value};

/// Request parameters
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(untagged)]
pub enum Params {
    /// No parameters
    None,
    /// Array of values
    Array(Vec<JsonValue>),
    /// Map of values
    Map(serde_json::Map<String, JsonValue>),
}

impl Params {
    /// Parse incoming `Params` into expected common.
    pub fn parse<D>(self) -> Result<D, Error>
    where
        D: DeserializeOwned,
    {
        let value: JsonValue = self.into();
        from_value(value).map_err(|e| Error::InvalidParams(format!("Invalid params: {}.", e)))
    }

    pub fn to_value(&self) -> Value {
        match self {
            Params::None => JsonValue::Null,
            Params::Array(a) => Value::Array(a.clone()),
            Params::Map(a) => Value::Object(a.clone()),
        }
    }

    /// Check for no params, returns Err if any params
    pub fn expect_no_params(self) -> Result<(), Error> {
        match self {
            Params::None => Ok(()),
            Params::Array(ref v) if v.is_empty() => Ok(()),
            _ => Err(Error::InvalidParams(
                "No parameters were expected".to_string(),
            )),
        }
    }
}

impl From<Params> for JsonValue {
    fn from(params: Params) -> JsonValue {
        match params {
            Params::Array(vec) => JsonValue::Array(vec),
            Params::Map(map) => JsonValue::Object(map),
            Params::None => JsonValue::Null,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Params;
    use crate::common::{Error, ErrorCode, JsonValue};
    use serde_json;

    #[test]
    fn params_deserialization() {
        let s = r#"[null, true, -1, 4, 2.3, "hello", [0], {"key": "value"}, []]"#;
        let deserialized: Params = serde_json::from_str(s).unwrap();

        let mut map = serde_json::Map::new();
        map.insert("key".to_string(), JsonValue::String("value".to_string()));

        assert_eq!(
            Params::Array(vec![
                JsonValue::Null,
                JsonValue::Bool(true),
                JsonValue::from(-1),
                JsonValue::from(4),
                JsonValue::from(2.3),
                JsonValue::String("hello".to_string()),
                JsonValue::Array(vec![JsonValue::from(0)]),
                JsonValue::Object(map),
                JsonValue::Array(vec![]),
            ]),
            deserialized
        );
    }

    #[test]
    fn should_return_meaningful_error_when_deserialization_fails() {
        // given
        let s = r#"[1, true]"#;
        let params = || serde_json::from_str::<Params>(s).unwrap();

        // when
        let v1: Result<(Option<u8>, String), Error> = params().parse();
        let v2: Result<(u8, bool, String), Error> = params().parse();
        let err1 = v1.unwrap_err();
        let err2 = v2.unwrap_err();

        // then
        assert_eq!(err1.code, ErrorCode::InvalidParams);
        assert_eq!(
            err1.message,
            "Invalid params: invalid type: boolean `true`, expected a string."
        );
        assert_eq!(err1.data, None);
        assert_eq!(err2.code, ErrorCode::InvalidParams);
        assert_eq!(
            err2.message,
            "Invalid params: invalid length 2, expected a tuple of size 3."
        );
        assert_eq!(err2.data, None);
    }

    #[test]
    fn single_param_parsed_as_tuple() {
        let params: (u64,) = Params::Array(vec![JsonValue::from(1)]).parse().unwrap();
        assert_eq!(params, (1,));
    }
}