jsonrpc_pubsub/
types.rs

1use crate::core;
2use crate::core::futures::channel::mpsc;
3use std::sync::Arc;
4
5use crate::subscription::Session;
6
7/// Raw transport sink for specific client.
8pub type TransportSender = mpsc::UnboundedSender<String>;
9/// Raw transport error.
10pub type TransportError = mpsc::SendError;
11/// Subscription send result.
12pub type SinkResult = Result<(), mpsc::TrySendError<String>>;
13
14/// Metadata extension for pub-sub method handling.
15///
16/// NOTE storing `PubSubMetadata` (or rather storing `Arc<Session>`) in
17/// any other place outside of the handler will prevent `unsubscribe` methods
18/// to be called in case the `Session` is dropped (i.e. transport connection is closed).
19pub trait PubSubMetadata: core::Metadata {
20	/// Returns session object associated with given request/client.
21	/// `None` indicates that sessions are not supported on the used transport.
22	fn session(&self) -> Option<Arc<Session>>;
23}
24
25impl PubSubMetadata for Arc<Session> {
26	fn session(&self) -> Option<Arc<Session>> {
27		Some(self.clone())
28	}
29}
30
31impl<T: PubSubMetadata> PubSubMetadata for Option<T> {
32	fn session(&self) -> Option<Arc<Session>> {
33		self.as_ref().and_then(|s| s.session())
34	}
35}
36
37/// Unique subscription id.
38///
39/// NOTE Assigning same id to different requests will cause the previous request to be unsubscribed.
40#[derive(Debug, Clone, PartialEq, Eq, Hash)]
41pub enum SubscriptionId {
42	/// A numerical ID, represented by a `u64`.
43	Number(u64),
44	/// A non-numerical ID, for example a hash.
45	String(String),
46}
47
48impl SubscriptionId {
49	/// Parses `core::Value` into unique subscription id.
50	pub fn parse_value(val: &core::Value) -> Option<SubscriptionId> {
51		match *val {
52			core::Value::String(ref val) => Some(SubscriptionId::String(val.clone())),
53			core::Value::Number(ref val) => val.as_u64().map(SubscriptionId::Number),
54			_ => None,
55		}
56	}
57}
58
59impl From<String> for SubscriptionId {
60	fn from(other: String) -> Self {
61		SubscriptionId::String(other)
62	}
63}
64
65impl From<SubscriptionId> for core::Value {
66	fn from(sub: SubscriptionId) -> Self {
67		match sub {
68			SubscriptionId::Number(val) => core::Value::Number(val.into()),
69			SubscriptionId::String(val) => core::Value::String(val),
70		}
71	}
72}
73
74macro_rules! impl_from_num {
75	($num:ty) => {
76		impl From<$num> for SubscriptionId {
77			fn from(other: $num) -> Self {
78				SubscriptionId::Number(other.into())
79			}
80		}
81	};
82}
83
84impl_from_num!(u8);
85impl_from_num!(u16);
86impl_from_num!(u32);
87impl_from_num!(u64);
88
89#[cfg(test)]
90mod tests {
91	use super::SubscriptionId;
92	use crate::core::Value;
93
94	#[test]
95	fn should_convert_between_number_value_and_subscription_id() {
96		let val = Value::Number(5.into());
97		let res = SubscriptionId::parse_value(&val);
98
99		assert_eq!(res, Some(SubscriptionId::Number(5)));
100		assert_eq!(Value::from(res.unwrap()), val);
101	}
102
103	#[test]
104	fn should_convert_between_string_value_and_subscription_id() {
105		let val = Value::String("asdf".into());
106		let res = SubscriptionId::parse_value(&val);
107
108		assert_eq!(res, Some(SubscriptionId::String("asdf".into())));
109		assert_eq!(Value::from(res.unwrap()), val);
110	}
111
112	#[test]
113	fn should_convert_between_null_value_and_subscription_id() {
114		let val = Value::Null;
115		let res = SubscriptionId::parse_value(&val);
116		assert_eq!(res, None);
117	}
118
119	#[test]
120	fn should_convert_from_u8_to_subscription_id() {
121		let val = 5u8;
122		let res: SubscriptionId = val.into();
123		assert_eq!(res, SubscriptionId::Number(5));
124	}
125
126	#[test]
127	fn should_convert_from_u16_to_subscription_id() {
128		let val = 5u16;
129		let res: SubscriptionId = val.into();
130		assert_eq!(res, SubscriptionId::Number(5));
131	}
132
133	#[test]
134	fn should_convert_from_u32_to_subscription_id() {
135		let val = 5u32;
136		let res: SubscriptionId = val.into();
137		assert_eq!(res, SubscriptionId::Number(5));
138	}
139
140	#[test]
141	fn should_convert_from_u64_to_subscription_id() {
142		let val = 5u64;
143		let res: SubscriptionId = val.into();
144		assert_eq!(res, SubscriptionId::Number(5));
145	}
146
147	#[test]
148	fn should_convert_from_string_to_subscription_id() {
149		let val = "String".to_string();
150		let res: SubscriptionId = val.into();
151		assert_eq!(res, SubscriptionId::String("String".to_string()));
152	}
153}