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
123
124
125
126
127
128
129
130
131
use serde_json::value::RawValue;
use serde::Serialize;

/// A trait which is implemented for anything which can be turned into
/// valid RPC parameters.
pub trait IntoRpcParams {
    /// Return the params. These are expected to be encoded to JSON,
    /// and take the form of either an array or object of parameters.
    /// Can return `None` to avoid allocation when returning no parameters.
    fn into_rpc_params(self) -> RpcParams;
}

pub type RpcParams = Option<Box<RawValue>>;

/// Parameter builder to build valid "object or "named" parameters.
/// This is the equivalent of a JSON Map object `{ key: value }`.
///
/// # Examples
///
/// ```rust
///
/// use jsonrpc_client::params::ObjectParams;
///
/// let mut builder = ObjectParams::new();
/// builder.insert("param1", 1);
/// builder.insert("param2", "abc");
///
/// // Use RPC parameters...
/// ```
#[derive(Clone, Debug)]
pub struct ObjectParams {
    bytes: Vec<u8>
}

impl ObjectParams {
    /// Construct a new [`ObjectParams`] instance.
    pub fn new() -> Self {
        ObjectParams { bytes: Vec::new() }
    }

    /// Insert a new named parameter.
    pub fn insert<P: Serialize>(&mut self, name: &str, value: P) -> Result<(), serde_json::Error> {
        if self.bytes.is_empty() {
            self.bytes.push(b'{');
        } else {
            self.bytes.push(b',');
        }

        serde_json::to_writer(&mut self.bytes, name)?;
        self.bytes.push(b':');
        serde_json::to_writer(&mut self.bytes, &value)?;

        Ok(())
    }

    /// Build the final output.
    pub fn build(mut self) -> RpcParams {
        if self.bytes.is_empty() {
            return None;
        }

        self.bytes.push(b'}');
        // Safety: This is safe because JSON does not emit invalid UTF-8:
        let utf8_string = unsafe { String::from_utf8_unchecked(self.bytes) };
        Some(RawValue::from_string(utf8_string).expect("valid JSON expected"))
    }
}

impl IntoRpcParams for ObjectParams {
    fn into_rpc_params(self) -> RpcParams {
        self.build()
    }
}

/// Parameter builder to build valid "array" or "unnamed" JSON-RPC parameters.
/// This is the equivalent of a JSON array like `[ value0, value1, .., valueN ]`.
///
/// # Examples
///
/// ```rust
///
/// use jsonrpc_client::params::ArrayParams;
///
/// let mut builder = ArrayParams::new();
/// builder.insert("param1");
/// builder.insert(1);
///
/// // Use RPC parameters...
/// ```
#[derive(Clone, Debug)]
pub struct ArrayParams {
    bytes: Vec<u8>
}

impl ArrayParams {
    /// Construct a new [`ArrayParams`] instance.
    pub fn new() -> Self {
        ArrayParams { bytes: Vec::new() }
    }

    /// Insert a new parameter.
    pub fn insert<P: Serialize>(&mut self, value: P) -> Result<(), serde_json::Error> {
        if self.bytes.is_empty() {
            self.bytes.push(b'[');
        } else {
            self.bytes.push(b',');
        }

        serde_json::to_writer(&mut self.bytes, &value)?;

        Ok(())
    }

    /// Build the final output.
    pub fn build(mut self) -> RpcParams {
        if self.bytes.is_empty() {
            return None;
        }

        self.bytes.push(b']');
        // Safety: This is safe because JSON does not emit invalid UTF-8:
        let utf8_string = unsafe { String::from_utf8_unchecked(self.bytes) };
        Some(RawValue::from_string(utf8_string).expect("valid JSON expected"))
    }
}

impl IntoRpcParams for ArrayParams {
    fn into_rpc_params(self) -> RpcParams {
        self.build()
    }
}