jsonrpsee_types/
params.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27//! Types to handle JSON-RPC request parameters according to the [spec](https://www.jsonrpc.org/specification#parameter_structures).
28//! Some types come with a "*Ser" variant that implements [`serde::Serialize`]; these are used in the client.
29
30use std::borrow::Cow;
31use std::fmt;
32
33use serde::de::{self, Deserializer, Unexpected, Visitor};
34use serde::ser::Serializer;
35use serde::{Deserialize, Serialize};
36use serde_json::Value as JsonValue;
37
38use crate::error::{ErrorCode, INVALID_PARAMS_MSG};
39use crate::{ErrorObject, ErrorObjectOwned};
40
41/// JSON-RPC v2 marker type.
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
43pub struct TwoPointZero;
44
45struct TwoPointZeroVisitor;
46
47impl<'de> Visitor<'de> for TwoPointZeroVisitor {
48	type Value = TwoPointZero;
49
50	fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
51		formatter.write_str(r#"a string "2.0""#)
52	}
53
54	fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
55	where
56		E: de::Error,
57	{
58		match s {
59			"2.0" => Ok(TwoPointZero),
60			_ => Err(de::Error::invalid_value(Unexpected::Str(s), &self)),
61		}
62	}
63}
64
65impl<'de> Deserialize<'de> for TwoPointZero {
66	fn deserialize<D>(deserializer: D) -> Result<TwoPointZero, D::Error>
67	where
68		D: Deserializer<'de>,
69	{
70		deserializer.deserialize_str(TwoPointZeroVisitor)
71	}
72}
73
74impl Serialize for TwoPointZero {
75	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76	where
77		S: Serializer,
78	{
79		serializer.serialize_str("2.0")
80	}
81}
82
83/// Parameters sent with an incoming JSON-RPC request.
84///
85/// The data containing the params is a `Cow<&str>` and can either be a borrowed `&str` of JSON from an incoming
86/// [`super::request::Request`] (which in turn borrows it from the input buffer that is shared between requests);
87/// or, it can be an owned [`String`].
88#[derive(Clone, Debug)]
89pub struct Params<'a>(Option<Cow<'a, str>>);
90
91impl<'a> Params<'a> {
92	/// Create params
93	pub fn new(raw: Option<&'a str>) -> Self {
94		Self(raw.map(|r| r.trim().into()))
95	}
96
97	/// Returns true if the contained JSON is an object
98	pub fn is_object(&self) -> bool {
99		let json: &str = match self.0 {
100			Some(ref cow) => cow,
101			None => return false,
102		};
103		json.starts_with('{')
104	}
105
106	/// Obtain a sequence parser, [`ParamsSequence`].
107	///
108	/// This allows sequential parsing of the incoming params, using an `Iterator`-style API and is useful when the RPC
109	/// request has optional parameters at the tail that may or may not be present.
110	pub fn sequence(&self) -> ParamsSequence {
111		let json = match self.0.as_ref() {
112			// It's assumed that params is `[a,b,c]`, if empty regard as no params.
113			Some(json) if json == "[]" => "",
114			Some(json) => json,
115			None => "",
116		};
117		ParamsSequence(json)
118	}
119
120	/// Attempt to parse all parameters as an array or map into type `T`.
121	pub fn parse<T>(&'a self) -> Result<T, ErrorObjectOwned>
122	where
123		T: Deserialize<'a>,
124	{
125		// NOTE(niklasad1): Option::None is serialized as `null` so we provide that here.
126		let params = self.0.as_ref().map(AsRef::as_ref).unwrap_or("null");
127		serde_json::from_str(params).map_err(invalid_params)
128	}
129
130	/// Attempt to parse parameters as an array of a single value of type `T`, and returns that value.
131	pub fn one<T>(&'a self) -> Result<T, ErrorObjectOwned>
132	where
133		T: Deserialize<'a>,
134	{
135		self.parse::<[T; 1]>().map(|[res]| res)
136	}
137
138	/// Convert `Params<'a>` to `Params<'static>` so that it can be moved across threads.
139	///
140	/// This will cause an allocation if the params internally are using a borrowed JSON slice.
141	pub fn into_owned(self) -> Params<'static> {
142		Params(self.0.map(|s| Cow::Owned(s.into_owned())))
143	}
144
145	/// Return the length of underlying JSON string in number of bytes.
146	pub fn len_bytes(&self) -> usize {
147		match self.0 {
148			Some(ref cow) => cow.len(),
149			None => 0,
150		}
151	}
152
153	/// Return the underlying JSON string as a `&str`.
154	pub fn as_str(&self) -> Option<&str> {
155		match self.0 {
156			Some(ref cow) => Some(cow.as_ref()),
157			None => None,
158		}
159	}
160}
161
162/// An `Iterator`-like parser for a sequence of [`Params`].
163///
164/// This will parse the params one at a time, and allows for graceful handling of optional parameters at the tail; other
165/// use cases are likely better served by [`Params::parse`]. The reason this is not an actual [`Iterator`] is that
166/// params parsing (often) yields values of different types.
167///
168/// Regards empty array `[]` as no parameters provided.
169#[derive(Debug, Copy, Clone)]
170pub struct ParamsSequence<'a>(&'a str);
171
172impl<'a> ParamsSequence<'a> {
173	fn next_inner<T>(&mut self) -> Option<Result<T, ErrorObjectOwned>>
174	where
175		T: Deserialize<'a>,
176	{
177		let mut json = self.0;
178		match json.as_bytes().first()? {
179			b']' => {
180				self.0 = "";
181				return None;
182			}
183			b'[' | b',' => json = &json[1..],
184			_ => {
185				let errmsg = format!("Invalid params. Expected one of '[', ']' or ',' but found {json:?}");
186				return Some(Err(invalid_params(errmsg)));
187			}
188		}
189
190		let mut iter = serde_json::Deserializer::from_str(json).into_iter::<T>();
191
192		match iter.next()? {
193			Ok(value) => {
194				self.0 = json[iter.byte_offset()..].trim_start();
195
196				Some(Ok(value))
197			}
198			Err(e) => {
199				self.0 = "";
200				Some(Err(invalid_params(e)))
201			}
202		}
203	}
204
205	/// Parse the next parameter to type `T`
206	///
207	/// ```
208	/// # use jsonrpsee_types::params::Params;
209	/// let params = Params::new(Some(r#"[true, 10, "foo"]"#));
210	/// let mut seq = params.sequence();
211	///
212	/// let a: bool = seq.next().unwrap();
213	/// let b: i32 = seq.next().unwrap();
214	/// let c: &str = seq.next().unwrap();
215	///
216	/// assert_eq!(a, true);
217	/// assert_eq!(b, 10);
218	/// assert_eq!(c, "foo");
219	/// ```
220	#[allow(clippy::should_implement_trait)]
221	pub fn next<T>(&mut self) -> Result<T, ErrorObjectOwned>
222	where
223		T: Deserialize<'a>,
224	{
225		match self.next_inner() {
226			Some(result) => result,
227			None => Err(invalid_params("No more params")),
228		}
229	}
230
231	/// Parse the next optional parameter to type `Option<T>`.
232	///
233	/// The result will be `None` for `null`, and for missing values in the supplied JSON array.
234	///
235	/// ```
236	/// # use jsonrpsee_types::params::Params;
237	/// let params = Params::new(Some(r#"[1, 2, null]"#));
238	/// let mut seq = params.sequence();
239	///
240	/// let params: [Option<u32>; 4] = [
241	///     seq.optional_next().unwrap(),
242	///     seq.optional_next().unwrap(),
243	///     seq.optional_next().unwrap(),
244	///     seq.optional_next().unwrap(),
245	/// ];
246	///
247	/// assert_eq!(params, [Some(1), Some(2), None, None]);
248	/// ```
249	pub fn optional_next<T>(&mut self) -> Result<Option<T>, ErrorObjectOwned>
250	where
251		T: Deserialize<'a>,
252	{
253		match self.next_inner::<Option<T>>() {
254			Some(result) => result,
255			None => Ok(None),
256		}
257	}
258}
259
260/// Id of a subscription, communicated by the server.
261#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)]
262#[serde(deny_unknown_fields)]
263#[serde(untagged)]
264pub enum SubscriptionId<'a> {
265	/// Numeric id
266	Num(u64),
267	/// String id
268	#[serde(borrow)]
269	Str(Cow<'a, str>),
270}
271
272impl<'a> From<SubscriptionId<'a>> for JsonValue {
273	fn from(sub_id: SubscriptionId) -> Self {
274		match sub_id {
275			SubscriptionId::Num(n) => n.into(),
276			SubscriptionId::Str(s) => s.into_owned().into(),
277		}
278	}
279}
280
281impl<'a> From<u64> for SubscriptionId<'a> {
282	fn from(sub_id: u64) -> Self {
283		Self::Num(sub_id)
284	}
285}
286
287impl<'a> From<String> for SubscriptionId<'a> {
288	fn from(sub_id: String) -> Self {
289		Self::Str(sub_id.into())
290	}
291}
292
293impl<'a> TryFrom<JsonValue> for SubscriptionId<'a> {
294	type Error = ();
295
296	fn try_from(json: JsonValue) -> Result<SubscriptionId<'a>, ()> {
297		match json {
298			JsonValue::String(s) => Ok(SubscriptionId::Str(s.into())),
299			JsonValue::Number(n) => {
300				if let Some(n) = n.as_u64() {
301					Ok(SubscriptionId::Num(n))
302				} else {
303					Err(())
304				}
305			}
306			_ => Err(()),
307		}
308	}
309}
310
311impl<'a> SubscriptionId<'a> {
312	/// Convert `SubscriptionId<'a>` to `SubscriptionId<'static>` so that it can be moved across threads.
313	///
314	/// This can cause an allocation if the id is a string.
315	pub fn into_owned(self) -> SubscriptionId<'static> {
316		match self {
317			SubscriptionId::Num(num) => SubscriptionId::Num(num),
318			SubscriptionId::Str(s) => SubscriptionId::Str(Cow::Owned(s.into_owned())),
319		}
320	}
321}
322
323/// Represent a request that failed because of an invalid request id.
324#[derive(Debug, thiserror::Error)]
325pub enum InvalidRequestId {
326	/// The request ID was parsed as valid ID but not a pending request.
327	#[error("request ID={0} is not a pending call")]
328	NotPendingRequest(String),
329
330	/// The request ID was already assigned to a pending call.
331	#[error("request ID={0} is already occupied by a pending call")]
332	Occupied(String),
333
334	/// The request ID format was invalid.
335	#[error("request ID={0} is invalid")]
336	Invalid(String),
337}
338
339/// Request Id
340#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize, PartialOrd, Ord)]
341#[serde(deny_unknown_fields)]
342#[serde(untagged)]
343pub enum Id<'a> {
344	/// Null
345	Null,
346	/// Numeric id
347	Number(u64),
348	/// String id
349	#[serde(borrow)]
350	Str(Cow<'a, str>),
351}
352
353impl<'a> Id<'a> {
354	/// If the Id is a number, returns the associated number. Returns None otherwise.
355	pub fn as_number(&self) -> Option<&u64> {
356		match self {
357			Self::Number(n) => Some(n),
358			_ => None,
359		}
360	}
361
362	/// If the Id is a String, returns the associated str. Returns None otherwise.
363	pub fn as_str(&self) -> Option<&str> {
364		match self {
365			Self::Str(s) => Some(s.as_ref()),
366			_ => None,
367		}
368	}
369
370	/// If the ID is Null, returns (). Returns None otherwise.
371	pub fn as_null(&self) -> Option<()> {
372		match self {
373			Self::Null => Some(()),
374			_ => None,
375		}
376	}
377
378	/// Convert `Id<'a>` to `Id<'static>` so that it can be moved across threads.
379	///
380	/// This can cause an allocation if the id is a string.
381	pub fn into_owned(self) -> Id<'static> {
382		match self {
383			Id::Null => Id::Null,
384			Id::Number(num) => Id::Number(num),
385			Id::Str(s) => Id::Str(Cow::Owned(s.into_owned())),
386		}
387	}
388
389	/// Extract the underlying number from the ID.
390	pub fn try_parse_inner_as_number(&self) -> Result<u64, InvalidRequestId> {
391		match self {
392			Id::Null => Err(InvalidRequestId::Invalid("null".to_string())),
393			Id::Number(num) => Ok(*num),
394			Id::Str(s) => s.parse().map_err(|_| InvalidRequestId::Invalid(s.as_ref().to_owned())),
395		}
396	}
397}
398
399impl<'a> std::fmt::Display for Id<'a> {
400	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401		match self {
402			Id::Null => f.write_str("null"),
403			Id::Number(n) => f.write_str(&n.to_string()),
404			Id::Str(s) => f.write_str(s),
405		}
406	}
407}
408
409fn invalid_params(e: impl ToString) -> ErrorObjectOwned {
410	ErrorObject::owned(ErrorCode::InvalidParams.code(), INVALID_PARAMS_MSG, Some(e.to_string()))
411}
412
413#[cfg(test)]
414mod test {
415	use super::{Cow, Id, JsonValue, Params, SubscriptionId, TwoPointZero};
416	use crate::response::SubscriptionPayload;
417
418	#[test]
419	fn id_deserialization() {
420		let s = r#""2""#;
421		let deserialized: Id = serde_json::from_str(s).unwrap();
422		match deserialized {
423			Id::Str(ref cow) => {
424				assert!(matches!(cow, Cow::Borrowed(_)));
425				assert_eq!(cow, "2");
426			}
427			_ => panic!("Expected Id::Str"),
428		}
429
430		let s = r#"2"#;
431		let deserialized: Id = serde_json::from_str(s).unwrap();
432		assert_eq!(deserialized, Id::Number(2));
433
434		let s = r#""2x""#;
435		let deserialized: Id = serde_json::from_str(s).unwrap();
436		assert_eq!(deserialized, Id::Str(Cow::Borrowed("2x")));
437
438		let s = r#"[1337]"#;
439		assert!(serde_json::from_str::<Id>(s).is_err());
440
441		let s = r#"[null, 0, 2, "\"3"]"#;
442		let deserialized: Vec<Id> = serde_json::from_str(s).unwrap();
443		assert_eq!(deserialized, vec![Id::Null, Id::Number(0), Id::Number(2), Id::Str("\"3".into())]);
444	}
445
446	#[test]
447	fn id_serialization() {
448		let d =
449			vec![Id::Null, Id::Number(0), Id::Number(2), Id::Number(3), Id::Str("\"3".into()), Id::Str("test".into())];
450		let serialized = serde_json::to_string(&d).unwrap();
451		assert_eq!(serialized, r#"[null,0,2,3,"\"3","test"]"#);
452	}
453
454	#[test]
455	fn params_parse() {
456		let none = Params::new(None);
457		assert!(none.sequence().next::<u64>().is_err());
458		assert!(none.parse::<Option<u64>>().is_ok());
459		assert_eq!(none.len_bytes(), 0);
460
461		let array_params = Params::new(Some("[1, 2, 3]"));
462		assert_eq!(array_params.len_bytes(), 9);
463		let arr: Result<[u64; 3], _> = array_params.parse();
464		assert!(arr.is_ok());
465
466		let mut seq = array_params.sequence();
467
468		assert_eq!(seq.next::<u64>().unwrap(), 1);
469		assert_eq!(seq.next::<u64>().unwrap(), 2);
470		assert_eq!(seq.next::<u64>().unwrap(), 3);
471		assert!(seq.next::<u64>().is_err());
472
473		let array_one = Params::new(Some("[1]"));
474		assert_eq!(array_one.len_bytes(), 3);
475		let one: Result<u64, _> = array_one.one();
476		assert!(one.is_ok());
477
478		let object_params = Params::new(Some(r#"{"beef":99,"dinner":0}"#));
479		assert_eq!(object_params.len_bytes(), 22);
480		let obj: Result<JsonValue, _> = object_params.parse();
481		assert!(obj.is_ok());
482	}
483
484	#[test]
485	fn params_parse_empty_json() {
486		let array_params = Params::new(Some("[]"));
487		let arr: Result<Vec<u64>, _> = array_params.parse();
488		assert!(arr.is_ok());
489
490		let obj_params = Params::new(Some("{}"));
491		let obj: Result<JsonValue, _> = obj_params.parse();
492		assert!(obj.is_ok());
493	}
494
495	#[test]
496	fn params_sequence_borrows() {
497		let params = Params::new(Some(r#"["foo", "bar"]"#));
498		let mut seq = params.sequence();
499
500		assert_eq!(seq.next::<&str>().unwrap(), "foo");
501		assert_eq!(seq.next::<&str>().unwrap(), "bar");
502		assert!(seq.next::<&str>().is_err());
503
504		// It's ok to parse the params again.
505		let params: (&str, &str) = params.parse().unwrap();
506		assert_eq!(params, ("foo", "bar"));
507	}
508
509	#[test]
510	fn two_point_zero_serde_works() {
511		let initial_ser = r#""2.0""#;
512		// The fact that it was deserialized is enough.
513		let two_point_zero: TwoPointZero = serde_json::from_str(initial_ser).unwrap();
514		let serialized = serde_json::to_string(&two_point_zero).unwrap();
515		assert_eq!(serialized, initial_ser);
516	}
517
518	#[test]
519	fn subscription_id_serde_works() {
520		let test_vector = &[("42", SubscriptionId::Num(42)), (r#""one""#, SubscriptionId::Str("one".into()))];
521
522		for (initial_ser, expected) in test_vector {
523			let id: SubscriptionId = serde_json::from_str(initial_ser).unwrap();
524			assert_eq!(&id, expected);
525			let serialized = serde_json::to_string(&id).unwrap();
526			assert_eq!(&serialized, initial_ser);
527		}
528	}
529
530	#[test]
531	fn subscription_params_serialize_work() {
532		let ser = serde_json::to_string(&SubscriptionPayload { subscription: SubscriptionId::Num(12), result: "goal" })
533			.unwrap();
534		let exp = r#"{"subscription":12,"result":"goal"}"#;
535		assert_eq!(ser, exp);
536	}
537
538	#[test]
539	fn subscription_params_deserialize_work() {
540		let ser = r#"{"subscription":"9","result":"offside"}"#;
541		assert!(
542			serde_json::from_str::<SubscriptionPayload<()>>(ser).is_err(),
543			"invalid type should not be deserializable"
544		);
545		let dsr: SubscriptionPayload<JsonValue> = serde_json::from_str(ser).unwrap();
546		assert_eq!(dsr.subscription, SubscriptionId::Str("9".into()));
547		assert_eq!(dsr.result, serde_json::json!("offside"));
548	}
549
550	#[test]
551	fn params_sequence_optional_ignore_empty() {
552		let params = Params::new(Some(r#"["foo", "bar"]"#));
553		let mut seq = params.sequence();
554
555		assert_eq!(seq.optional_next::<&str>().unwrap(), Some("foo"));
556		assert_eq!(seq.optional_next::<&str>().unwrap(), Some("bar"));
557
558		let params = Params::new(Some(r#"[]"#));
559		let mut seq = params.sequence();
560		assert!(seq.optional_next::<&str>().unwrap().is_none());
561
562		let params = Params::new(Some(r#"   []		"#));
563		let mut seq = params.sequence();
564		assert!(seq.optional_next::<&str>().unwrap().is_none());
565
566		let params = Params::new(Some(r#"{}"#));
567		let mut seq = params.sequence();
568		assert!(seq.optional_next::<&str>().is_err(), "JSON object not supported by RpcSequence");
569
570		let params = Params::new(Some(r#"[12, "[]", [], {}]"#));
571		let mut seq = params.sequence();
572		assert_eq!(seq.optional_next::<u64>().unwrap(), Some(12));
573		assert_eq!(seq.optional_next::<&str>().unwrap(), Some("[]"));
574		assert_eq!(seq.optional_next::<Vec<u8>>().unwrap(), Some(vec![]));
575		assert_eq!(seq.optional_next::<serde_json::Value>().unwrap(), Some(serde_json::json!({})));
576	}
577
578	#[test]
579	fn params_sequence_optional_nesting_works() {
580		let nested = Params::new(Some(r#"[1, [2], [3, 4], [[5], [6,7], []], {"named":7}]"#));
581		let mut seq = nested.sequence();
582		assert_eq!(seq.optional_next::<i8>().unwrap(), Some(1));
583		assert_eq!(seq.optional_next::<[i8; 1]>().unwrap(), Some([2]));
584		assert_eq!(seq.optional_next::<Vec<u16>>().unwrap(), Some(vec![3, 4]));
585		assert_eq!(seq.optional_next::<Vec<Vec<u32>>>().unwrap(), Some(vec![vec![5], vec![6, 7], vec![]]));
586		assert_eq!(seq.optional_next::<serde_json::Value>().unwrap(), Some(serde_json::json!({"named":7})));
587	}
588}