ac_primitives/
rpc_params.rs1use alloc::{string::String, vec, vec::Vec};
32use serde::Serialize;
33use serde_json::{Result, Value};
34
35#[derive(Debug)]
36pub struct RpcParams(ParamsBuilder);
37
38impl RpcParams {
39 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn insert<P: Serialize>(&mut self, value: P) -> Result<()> {
46 self.0.insert(value)
47 }
48
49 pub fn insert_with_allocation<P: Serialize>(&mut self, value: P) -> Result<()> {
53 self.0.insert_with_allocation(value)
54 }
55
56 pub fn build(self) -> Option<String> {
58 self.0.build()
59 }
60
61 pub fn to_json_value(self) -> Result<Value> {
62 let params = match self.build() {
63 Some(string) => serde_json::from_str(&string)?,
64 None => serde_json::json!(vec![Value::Null]),
65 };
66 Ok(params)
67 }
68}
69
70impl Default for RpcParams {
71 fn default() -> Self {
72 Self(ParamsBuilder::positional())
73 }
74}
75const PARAM_BYTES_CAPACITY: usize = 128;
77
78#[derive(Debug)]
87pub(crate) struct ParamsBuilder {
88 bytes: Vec<u8>,
89 start: char,
90 end: char,
91}
92
93impl ParamsBuilder {
94 fn new(start: char, end: char) -> Self {
97 ParamsBuilder { bytes: Vec::new(), start, end }
98 }
99
100 pub(crate) fn positional() -> Self {
102 Self::new('[', ']')
103 }
104
105 fn maybe_initialize(&mut self) {
113 if self.bytes.is_empty() {
114 self.bytes.reserve(PARAM_BYTES_CAPACITY);
115 self.bytes.push(self.start as u8);
116 }
117 }
118
119 pub(crate) fn build(mut self) -> Option<String> {
121 if self.bytes.is_empty() {
122 return None
123 }
124
125 let idx = self.bytes.len() - 1;
126 if self.bytes[idx] == b',' {
127 self.bytes[idx] = self.end as u8;
128 } else {
129 self.bytes.push(self.end as u8);
130 }
131
132 Some(unsafe { String::from_utf8_unchecked(self.bytes) })
134 }
135
136 #[cfg(feature = "std")]
138 pub(crate) fn insert<P: Serialize>(&mut self, value: P) -> Result<()> {
139 self.maybe_initialize();
140
141 serde_json::to_writer(&mut self.bytes, &value)?;
142 self.bytes.push(b',');
143
144 Ok(())
145 }
146
147 #[cfg(not(feature = "std"))]
150 pub(crate) fn insert<P: Serialize>(&mut self, value: P) -> Result<()> {
151 self.insert_with_allocation(value)
152 }
153
154 pub(crate) fn insert_with_allocation<P: Serialize>(&mut self, value: P) -> Result<()> {
157 self.maybe_initialize();
158
159 let mut serialized_vec = serde_json::to_vec(&value)?;
160 self.bytes.append(&mut serialized_vec);
161 self.bytes.push(b',');
162
163 Ok(())
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn default_params_returns_none() {
173 let params = RpcParams::new();
174 let built_params = params.build();
175 assert!(built_params.is_none());
176 }
177
178 #[test]
179 fn insert_single_param_works() {
180 let mut params = RpcParams::new();
181 params.insert(Some(0)).unwrap();
182 let built_params = params.build().unwrap();
183 assert_eq!(built_params, "[0]".to_string());
184 }
185
186 #[test]
187 fn insert_multiple_params_works() {
188 let mut params = RpcParams::new();
189 params.insert(Some(0)).unwrap();
190 params.insert(0).unwrap();
191 let built_params = params.build().unwrap();
192 assert_eq!(built_params, "[0,0]".to_string());
193 }
194
195 #[test]
196 fn insert_with_allocation_multiple_params_works() {
197 let mut params = RpcParams::new();
198 params.insert_with_allocation(Some(0)).unwrap();
199 params.insert_with_allocation(0).unwrap();
200 let built_params = params.build().unwrap();
201 assert_eq!(built_params, "[0,0]".to_string());
202 }
203}