use crate::error::InvalidParams; use alloc::collections::BTreeMap; use serde::de::{self, Deserializer, Unexpected, Visitor}; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use serde_json::{value::RawValue, Value as JsonValue}; use std::fmt; /// JSON-RPC parameter values for subscriptions. #[derive(Serialize, Deserialize, Debug)] pub struct JsonRpcNotificationParams<'a> { /// Subscription ID pub subscription: u64, /// Result. #[serde(borrow)] pub result: &'a RawValue, } /// JSON-RPC parameter values for subscriptions with support for number and strings. #[derive(Deserialize, Debug)] pub struct JsonRpcNotificationParamsAlloc { /// Subscription ID pub subscription: SubscriptionId, /// Result. pub result: T, } /// JSON-RPC v2 marker type. #[derive(Debug, Default, PartialEq)] pub struct TwoPointZero; struct TwoPointZeroVisitor; impl<'de> Visitor<'de> for TwoPointZeroVisitor { type Value = TwoPointZero; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(r#"a string "2.0""#) } fn visit_str(self, s: &str) -> Result where E: de::Error, { match s { "2.0" => Ok(TwoPointZero), _ => Err(de::Error::invalid_value(Unexpected::Str(s), &self)), } } } impl<'de> Deserialize<'de> for TwoPointZero { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_str(TwoPointZeroVisitor) } } impl Serialize for TwoPointZero { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_str("2.0") } } /// Parameters sent with the RPC request #[derive(Clone, Copy, Debug)] pub struct RpcParams<'a>(Option<&'a str>); impl<'a> RpcParams<'a> { /// Create params pub fn new(raw: Option<&'a str>) -> Self { Self(raw) } /// Attempt to parse all parameters as array or map into type T pub fn parse(self) -> Result where T: Deserialize<'a>, { match self.0 { None => Err(InvalidParams), Some(params) => serde_json::from_str(params).map_err(|_| InvalidParams), } } /// Attempt to parse only the first parameter from an array into type T pub fn one(self) -> Result where T: Deserialize<'a>, { self.parse::<[T; 1]>().map(|[res]| res) } } /// [Serializable JSON-RPC parameters](https://www.jsonrpc.org/specification#parameter_structures) /// /// If your type implement `Into` call that favor of `serde_json::to:value` to /// construct the parameters. Because `serde_json::to_value` serializes the type which /// allocates whereas `Into` doesn't in most cases. #[derive(Serialize, Debug, Clone)] #[serde(untagged)] pub enum JsonRpcParams<'a> { /// No params. NoParams, /// Positional params (heap allocated) Array(Vec), /// Positional params (slice) ArrayRef(&'a [JsonValue]), /// Params by name. Map(BTreeMap<&'a str, JsonValue>), } impl<'a> From> for JsonRpcParams<'a> { fn from(map: BTreeMap<&'a str, JsonValue>) -> Self { Self::Map(map) } } impl<'a> From> for JsonRpcParams<'a> { fn from(arr: Vec) -> Self { Self::Array(arr) } } impl<'a> From<&'a [JsonValue]> for JsonRpcParams<'a> { fn from(slice: &'a [JsonValue]) -> Self { Self::ArrayRef(slice) } } /// Id of a subscription, communicated by the server. #[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum SubscriptionId { /// Numeric id Num(u64), /// String id Str(String), } impl From for JsonValue { fn from(sub_id: SubscriptionId) -> Self { match sub_id { SubscriptionId::Num(n) => n.into(), SubscriptionId::Str(s) => s.into(), } } } /// Request Id #[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum Id { /// Null Null, /// Numeric id Number(u64), /// String id Str(String), } impl Id { /// If the Id is a number, returns the associated number. Returns None otherwise. pub fn as_number(&self) -> Option<&u64> { match self { Id::Number(n) => Some(n), _ => None, } } /// If the Id is a String, returns the associated str. Returns None otherwise. pub fn as_str(&self) -> Option<&str> { match self { Id::Str(s) => Some(s), _ => None, } } /// If the ID is Null, returns (). Returns None otherwise. pub fn as_null(&self) -> Option<()> { match self { Id::Null => Some(()), _ => None, } } } /// Untyped JSON-RPC ID. // TODO(niklasad1): this should be enforced to only accept: String, Number, or Null. pub type JsonRpcRawId<'a> = Option<&'a serde_json::value::RawValue>;