jsonrpc_macros/
auto_args.rs

1// because we reuse the type names as idents in the macros as a dirty hack to
2// work around `concat_idents!` being unstable.
3#![allow(non_snake_case)]
4
5///! Automatically serialize and deserialize parameters around a strongly-typed function.
6
7use jsonrpc_core::{Error, Params, Value, Metadata};
8use jsonrpc_core::futures::{self, BoxFuture, Future};
9use jsonrpc_pubsub::{PubSubMetadata, Subscriber};
10use pubsub;
11use serde::Serialize;
12use serde::de::DeserializeOwned;
13use util::{invalid_params, expect_no_params, to_value};
14
15/// Auto-generates an RPC trait from trait definition.
16///
17/// This just copies out all the methods, docs, and adds another
18/// function `to_delegate` which will automatically wrap each strongly-typed
19/// function in a wrapper which handles parameter and output type serialization.
20///
21/// RPC functions may come in a couple forms: synchronous, async and async with metadata.
22/// These are parsed with the custom `#[rpc]` attribute, which must follow
23/// documentation.
24///
25/// ## The #[rpc] attribute
26///
27/// Valid forms:
28///  - `#[rpc(name = "name_here")]` (a synchronous rpc function which should be bound to the given name)
29///  - `#[rpc(async, name = "name_here")]` (an async rpc function which should be bound to the given name)
30///  - `#[rpc(meta, name = "name_here")]` (an async rpc function with metadata which should be bound to the given name)
31///
32/// Synchronous function format:
33/// `fn foo(&self, Param1, Param2, Param3) -> Result<Out, Error>`.
34///
35/// Asynchronous RPC functions must come in this form:
36/// `fn foo(&self, Param1, Param2, Param3) -> BoxFuture<Out, Error>;
37///
38/// Asynchronous RPC functions with metadata must come in this form:
39/// `fn foo(&self, Self::Metadata, Param1, Param2, Param3) -> BoxFuture<Out, Error>;
40///
41/// Anything else will be rejected by the code generator.
42///
43/// ## The #[pubsub] attribute
44///
45/// Valid form:
46/// ```rust,ignore
47///	#[pubsub(name = "hello")] {
48///	  #[rpc(name = "hello_subscribe")]
49///	  fn subscribe(&self, Self::Metadata, pubsub::Subscriber<String>, u64);
50///	  #[rpc(name = "hello_unsubscribe")]
51///	  fn unsubscribe(&self, SubscriptionId) -> BoxFuture<bool, Error>;
52///	}
53///	```
54///
55/// The attribute is used to create a new pair of subscription methods
56/// (if underlying transport supports that.)
57
58
59#[macro_export]
60macro_rules! metadata {
61	() => {
62		/// Requests metadata
63		type Metadata: ::jsonrpc_core::Metadata;
64	};
65	(
66		$( $sub_name: ident )+
67	) => {
68		/// Requests metadata
69		type Metadata: ::jsonrpc_pubsub::PubSubMetadata;
70	};
71}
72
73#[macro_export]
74macro_rules! build_rpc_trait {
75	// entry-point. todo: make another for traits w/ bounds.
76	(
77		$(#[$t_attr: meta])*
78		pub trait $name: ident {
79			$(
80				$( #[doc=$m_doc:expr] )*
81				#[ rpc( $($t:tt)* ) ]
82				fn $m_name: ident ( $($p: tt)* ) -> $result: tt <$out: ty, $error: ty>;
83			)*
84		}
85	) => {
86		$(#[$t_attr])*
87		pub trait $name: Sized + Send + Sync + 'static {
88			$(
89				$(#[doc=$m_doc])*
90				fn $m_name ( $($p)* ) -> $result<$out, $error> ;
91			)*
92
93			/// Transform this into an `IoDelegate`, automatically wrapping
94			/// the parameters.
95			fn to_delegate<M: ::jsonrpc_core::Metadata>(self) -> $crate::IoDelegate<Self, M> {
96				let mut del = $crate::IoDelegate::new(self.into());
97				$(
98					build_rpc_trait!(WRAP del =>
99						( $($t)* )
100						fn $m_name ( $($p)* ) -> $result <$out, $error>
101					);
102				)*
103				del
104			}
105		}
106	};
107
108	// entry-point for trait with metadata methods
109	(
110		$(#[$t_attr: meta])*
111		pub trait $name: ident {
112			type Metadata;
113
114			$(
115				$( #[ doc=$m_doc:expr ] )*
116				#[ rpc( $($t:tt)* ) ]
117				fn $m_name: ident ( $($p: tt)* ) -> $result: tt <$out: ty, $error_std: ty>;
118			)*
119
120			$(
121				#[ pubsub( $($pubsub_t:tt)+ ) ] {
122					$( #[ doc= $sub_doc:expr ] )*
123					#[ rpc( $($sub_t:tt)* ) ]
124					fn $sub_name: ident ( $($sub_p: tt)* );
125					$( #[ doc= $unsub_doc:expr ] )*
126					#[ rpc( $($unsub_t:tt)* ) ]
127					fn $unsub_name: ident ( $($unsub_p: tt)* ) -> $sub_result: tt <$sub_out: ty, $error_unsub: ty>;
128				}
129			)*
130
131		}
132	) => {
133		$(#[$t_attr])*
134		pub trait $name: Sized + Send + Sync + 'static {
135			// Metadata bound differs for traits with subscription methods.
136			metadata! (
137				$( $sub_name )*
138			);
139
140			$(
141				$(#[doc=$m_doc])*
142				fn $m_name ( $($p)* ) -> $result <$out, $error_std>;
143			)*
144
145			$(
146				$(#[doc=$sub_doc])*
147				fn $sub_name ( $($sub_p)* );
148				$(#[doc=$unsub_doc])*
149				fn $unsub_name ( $($unsub_p)* ) -> $sub_result <$sub_out, $error_unsub>;
150			)*
151
152			/// Transform this into an `IoDelegate`, automatically wrapping
153			/// the parameters.
154			fn to_delegate(self) -> $crate::IoDelegate<Self, Self::Metadata> {
155				let mut del = $crate::IoDelegate::new(self.into());
156				$(
157					build_rpc_trait!(WRAP del =>
158						( $($t)* )
159						fn $m_name ( $($p)* ) -> $result <$out, $error_std>
160					);
161				)*
162				$(
163					build_rpc_trait!(WRAP del =>
164						pubsub: ( $($pubsub_t)* )
165						subscribe: ( $($sub_t)* )
166						fn $sub_name ( $($sub_p)* );
167						unsubscribe: ( $($unsub_t)* )
168						fn $unsub_name ( $($unsub_p)* ) -> $sub_result <$sub_out, $error_unsub>;
169					);
170				)*
171				del
172			}
173		}
174	};
175
176	( WRAP $del: expr =>
177		(name = $name: expr $(, alias = [ $( $alias: expr, )+ ])*)
178		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, $error: ty>
179	) => {
180		$del.add_method($name, move |base, params| {
181			$crate::Wrap::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, $error>), base, params)
182		});
183		$(
184			$(
185				$del.add_alias($alias, $name);
186			)+
187		)*
188	};
189
190	( WRAP $del: expr =>
191		(async, name = $name: expr $(, alias = [ $( $alias: expr, )+ ])*)
192		fn $method: ident (&self $(, $param: ty)*) -> $result: tt <$out: ty, $error: ty>
193	) => {
194		$del.add_async_method($name, move |base, params| {
195			$crate::WrapAsync::wrap_rpc(&(Self::$method as fn(&_ $(, $param)*) -> $result <$out, $error>), base, params)
196		});
197		$(
198			$(
199				$del.add_alias($alias, $name);
200			)+
201		)*
202	};
203
204	( WRAP $del: expr =>
205		(meta, name = $name: expr $(, alias = [ $( $alias: expr, )+ ])*)
206		fn $method: ident (&self, Self::Metadata $(, $param: ty)*) -> $result: tt <$out: ty, $error: ty>
207	) => {
208		$del.add_method_with_meta($name, move |base, params, meta| {
209			$crate::WrapMeta::wrap_rpc(&(Self::$method as fn(&_, Self::Metadata $(, $param)*) -> $result <$out, Error>), base, params, meta)
210		});
211		$(
212			$(
213				$del.add_alias($alias, $name);
214			)+
215		)*
216	};
217
218	( WRAP $del: expr =>
219		pubsub: (name = $name: expr)
220		subscribe: (name = $subscribe: expr $(, alias = [ $( $sub_alias: expr, )+ ])*)
221		fn $sub_method: ident (&self, Self::Metadata $(, $sub_p: ty)+);
222		unsubscribe: (name = $unsubscribe: expr $(, alias = [ $( $unsub_alias: expr, )+ ])*)
223		fn $unsub_method: ident (&self $(, $unsub_p: ty)+) -> $result: tt <$out: ty, $error_unsub: ty>;
224	) => {
225		$del.add_subscription(
226			$name,
227			($subscribe, move |base, params, meta, subscriber| {
228				$crate::WrapSubscribe::wrap_rpc(
229					&(Self::$sub_method as fn(&_, Self::Metadata $(, $sub_p)*)),
230					base,
231					params,
232					meta,
233					subscriber,
234				)
235			}),
236			($unsubscribe, move |base, id| {
237				use $crate::jsonrpc_core::futures::Future;
238				Self::$unsub_method(base, id).map($crate::to_value).boxed()
239			}),
240		);
241
242		$(
243			$(
244				$del.add_alias($sub_alias, $subscribe);
245			)*
246		)*
247		$(
248			$(
249				$del.add_alias($unsub_alias, $unsubscribe);
250			)*
251		)*
252	};
253}
254
255/// A wrapper type without an implementation of `Deserialize`
256/// which allows a special implementation of `Wrap` for functions
257/// that take a trailing default parameter.
258pub struct Trailing<T>(Option<T>);
259
260impl<T> Into<Option<T>> for Trailing<T> {
261	fn into(self) -> Option<T> {
262		self.0
263	}
264}
265
266impl<T: DeserializeOwned> Trailing<T> {
267	/// Returns a underlying value if present or provided value.
268	pub fn unwrap_or(self, other: T) -> T {
269		self.0.unwrap_or(other)
270	}
271
272	/// Returns an underlying value or computes it if not present.
273	pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
274		self.0.unwrap_or_else(f)
275	}
276}
277
278impl<T: Default + DeserializeOwned> Trailing<T> {
279	/// Returns an underlying value or the default value.
280	pub fn unwrap_or_default(self) -> T {
281		self.0.unwrap_or_default()
282	}
283}
284
285/// Wrapper trait for synchronous RPC functions.
286pub trait Wrap<B> {
287	/// Invokes RPC method.
288	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
289}
290
291/// Wrapper trait for asynchronous RPC functions.
292pub trait WrapAsync<B> {
293	/// Invokes asynchronous RPC method.
294	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error>;
295}
296
297/// Wrapper trait for meta RPC functions.
298pub trait WrapMeta<B, M> {
299	/// Invokes asynchronous RPC method with Metadata.
300	fn wrap_rpc(&self, base: &B, params: Params, meta: M) -> BoxFuture<Value, Error>;
301}
302
303/// Wrapper trait for subscribe RPC functions.
304pub trait WrapSubscribe<B, M> {
305	/// Invokes subscription.
306	fn wrap_rpc(&self, base: &B, params: Params, meta: M, subscriber: Subscriber);
307}
308
309// special impl for no parameters.
310impl<B, OUT, E> Wrap<B> for fn(&B) -> Result<OUT, E>
311	where B: Send + Sync + 'static, OUT: Serialize + 'static, E: Into<Error> + 'static
312{
313	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
314        match expect_no_params(params) {
315            Ok(()) => (self)(base).map(to_value).map_err(Into::into),
316            Err(e) => Err(e),
317        }
318	}
319}
320
321impl<B, OUT, E> WrapAsync<B> for fn(&B) -> BoxFuture<OUT, E>
322	where B: Send + Sync + 'static, OUT: Serialize + 'static, E: Into<Error> + 'static
323{
324	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
325		match expect_no_params(params) {
326			Ok(()) => (self)(base).map(to_value).map_err(Into::into).boxed(),
327			Err(e) => futures::failed(e).boxed(),
328		}
329	}
330}
331
332impl<B, M, OUT, E> WrapMeta<B, M> for fn(&B, M) -> BoxFuture<OUT, E>
333	where B: Send + Sync + 'static, OUT: Serialize + 'static, M: Metadata, E: Into<Error> + 'static
334{
335	fn wrap_rpc(&self, base: &B, params: Params, meta: M) -> BoxFuture<Value, Error> {
336		match expect_no_params(params) {
337			Ok(()) => (self)(base, meta).map(to_value).map_err(Into::into).boxed(),
338			Err(e) => futures::failed(e.into()).boxed(),
339		}
340	}
341}
342
343impl<B, M, OUT> WrapSubscribe<B, M> for fn(&B, M, pubsub::Subscriber<OUT>)
344	where B: Send + Sync + 'static, OUT: Serialize, M: PubSubMetadata
345{
346	fn wrap_rpc(&self, base: &B, params: Params, meta: M, subscriber: Subscriber) {
347		match expect_no_params(params) {
348			Ok(()) => (self)(base, meta, pubsub::Subscriber::new(subscriber)),
349			Err(e) => {
350				let _ = subscriber.reject(e);
351			},
352		}
353	}
354}
355
356// creates a wrapper implementation which deserializes the parameters,
357// calls the function with concrete type, and serializes the output.
358macro_rules! wrap {
359	($($x: ident),+) => {
360
361		// synchronous implementation
362		impl <
363			BASE: Send + Sync + 'static,
364			OUT: Serialize + 'static,
365		    $($x: DeserializeOwned,)+
366            ERR: Into<Error> + 'static,
367		> Wrap<BASE> for fn(&BASE, $($x,)+) -> Result<OUT, ERR> {
368			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
369                match params.parse::<($($x,)+)>() {
370                    Ok(($($x,)+)) => (self)(base, $($x,)+).map(to_value).map_err(Into::into),
371                    Err(e) => Err(e)
372                }
373			}
374		}
375
376		// asynchronous implementation
377		impl <
378			BASE: Send + Sync + 'static,
379			OUT: Serialize + 'static,
380		    $($x: DeserializeOwned,)+
381            ERR: Into<Error> + 'static
382		> WrapAsync<BASE> for fn(&BASE, $($x,)+ ) -> BoxFuture<OUT, ERR> {
383			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
384				match params.parse::<($($x,)+)>() {
385					Ok(($($x,)+)) => (self)(base, $($x,)+).map(to_value).map_err(Into::into).boxed(),
386					Err(e) => futures::failed(e).boxed(),
387				}
388			}
389		}
390
391		// asynchronous implementation with meta
392		impl <
393			BASE: Send + Sync + 'static,
394			META: Metadata,
395			OUT: Serialize + 'static,
396		    $($x: DeserializeOwned,)+
397            ERR: Into<Error> + 'static
398		> WrapMeta<BASE, META> for fn(&BASE, META, $($x,)+) -> BoxFuture<OUT, ERR> {
399			fn wrap_rpc(&self, base: &BASE, params: Params, meta: META) -> BoxFuture<Value, Error> {
400				match params.parse::<($($x,)+)>() {
401					Ok(($($x,)+)) => (self)(base, meta, $($x,)+).map(to_value).map_err(Into::into).boxed(),
402					Err(e) => futures::failed(e).boxed(),
403				}
404			}
405		}
406
407		// subscribe implementation
408		impl <
409			BASE: Send + Sync + 'static,
410			META: PubSubMetadata,
411			OUT: Serialize,
412			$($x: DeserializeOwned,)+
413		> WrapSubscribe<BASE, META> for fn(&BASE, META, pubsub::Subscriber<OUT>, $($x,)+) {
414			fn wrap_rpc(&self, base: &BASE, params: Params, meta: META, subscriber: Subscriber){
415				match params.parse::<($($x,)+)>() {
416					Ok(($($x,)+)) => (self)(base, meta, pubsub::Subscriber::new(subscriber), $($x,)+),
417					Err(e) => {
418						let _ = subscriber.reject(e);
419					},
420				}
421			}
422		}
423	}
424}
425
426fn params_len(params: &Params) -> Result<usize, Error> {
427	match *params {
428		Params::Array(ref v) => Ok(v.len()),
429		Params::None => Ok(0),
430		_ => Err(invalid_params("`params` should be an array", "")),
431	}
432}
433
434fn require_len(params: &Params, required: usize) -> Result<usize, Error> {
435	let len = params_len(params)?;
436	if len < required {
437		return Err(invalid_params(&format!("`params` should have at least {} argument(s)", required), ""));
438	}
439	Ok(len)
440}
441
442fn parse_trailing_param<T: DeserializeOwned>(params: Params) -> Result<(Option<T>, ), Error> {
443	let len = try!(params_len(&params));
444	let id = match len {
445		0 => Ok((None,)),
446		1 => params.parse::<(T,)>().map(|(x, )| (Some(x), )),
447		_ => Err(invalid_params("Expecting only one optional parameter.", "")),
448	};
449
450	id
451}
452
453// special impl for no parameters other than block parameter.
454impl<B, OUT, T, E> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, E>
455	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: DeserializeOwned, E: Into<Error> + 'static
456{
457	fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
458		let id = try!(parse_trailing_param(params)).0;
459
460		(self)(base, Trailing(id)).map(to_value).map_err(Into::into)
461	}
462}
463
464impl<B, OUT, T, E> WrapAsync<B> for fn(&B, Trailing<T>) -> BoxFuture<OUT, E>
465	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: DeserializeOwned, E: Into<Error> + 'static
466{
467	fn wrap_rpc(&self, base: &B, params: Params) -> BoxFuture<Value, Error> {
468		let id = parse_trailing_param(params);
469
470		match id {
471			Ok((id,)) => (self)(base, Trailing(id)).map(to_value).map_err(Into::into).boxed(),
472			Err(e) => futures::failed(e).boxed(),
473		}
474	}
475}
476
477impl<B, M, OUT, T, E> WrapMeta<B, M> for fn(&B, M, Trailing<T>) -> BoxFuture<OUT, E>
478	where B: Send + Sync + 'static, OUT: Serialize + 'static, T: DeserializeOwned, M: Metadata, E: Into<Error> + 'static
479{
480	fn wrap_rpc(&self, base: &B, params: Params, meta: M) -> BoxFuture<Value, Error> {
481		let id = parse_trailing_param(params);
482
483		match id {
484			Ok((id,)) => (self)(base, meta, Trailing(id)).map(to_value).map_err(Into::into).boxed(),
485			Err(e) => futures::failed(e).boxed(),
486		}
487	}
488}
489
490impl<B, M, OUT, T> WrapSubscribe<B, M> for fn(&B, M, pubsub::Subscriber<OUT>, Trailing<T>)
491	where B: Send + Sync + 'static, OUT: Serialize, M: PubSubMetadata, T: DeserializeOwned,
492{
493	fn wrap_rpc(&self, base: &B, params: Params, meta: M, subscriber: Subscriber) {
494		let id = parse_trailing_param(params);
495
496		match id {
497			Ok((id,)) => (self)(base, meta, pubsub::Subscriber::new(subscriber), Trailing(id)),
498			Err(e) => {
499				let _ = subscriber.reject(e);
500			},
501		}
502	}
503}
504
505// similar to `wrap!`, but handles a single default trailing parameter
506// accepts an additional argument indicating the number of non-trailing parameters.
507macro_rules! wrap_with_trailing {
508	($num: expr, $($x: ident),+) => {
509		// synchronous implementation
510		impl <
511			BASE: Send + Sync + 'static,
512			OUT: Serialize + 'static,
513			$($x: DeserializeOwned,)+
514			TRAILING: DeserializeOwned,
515            ERR: Into<Error> + 'static
516		> Wrap<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> Result<OUT, ERR> {
517			fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
518				let len = require_len(&params, $num)?;
519
520				let params = match len - $num {
521					0 => params.parse::<($($x,)+)>()
522						.map(|($($x,)+)| ($($x,)+ None)).map_err(Into::into),
523					1 => params.parse::<($($x,)+ TRAILING)>()
524						.map(|($($x,)+ id)| ($($x,)+ Some(id))).map_err(Into::into),
525					_ => Err(invalid_params(&format!("Expected {} or {} parameters.", $num, $num + 1), format!("Got: {}", len))),
526				};
527
528				let ($($x,)+ id) = try!(params);
529				(self)(base, $($x,)+ Trailing(id)).map(to_value).map_err(Into::into)
530			}
531		}
532
533		// asynchronous implementation
534		impl <
535			BASE: Send + Sync + 'static,
536			OUT: Serialize + 'static,
537			$($x: DeserializeOwned,)+
538			TRAILING: DeserializeOwned,
539            ERR: Into<Error> + 'static
540		> WrapAsync<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> BoxFuture<OUT, ERR> {
541			fn wrap_rpc(&self, base: &BASE, params: Params) -> BoxFuture<Value, Error> {
542				let len = match require_len(&params, $num) {
543					Ok(len) => len,
544					Err(e) => return futures::failed(e).boxed(),
545				};
546
547				let params = match len - $num {
548					0 => params.parse::<($($x,)+)>()
549						.map(|($($x,)+)| ($($x,)+ None)).map_err(Into::into),
550					1 => params.parse::<($($x,)+ TRAILING)>()
551						.map(|($($x,)+ id)| ($($x,)+ Some(id))).map_err(Into::into),
552					_ => Err(invalid_params(&format!("Expected {} or {} parameters.", $num, $num + 1), format!("Got: {}", len))),
553				};
554
555				match params {
556					Ok(($($x,)+ id)) => (self)(base, $($x,)+ Trailing(id)).map(to_value).map_err(Into::into).boxed(),
557					Err(e) => futures::failed(e).boxed(),
558				}
559			}
560		}
561
562		// asynchronous implementation with meta
563		impl <
564			BASE: Send + Sync + 'static,
565			META: Metadata,
566			OUT: Serialize + 'static,
567			$($x: DeserializeOwned,)+
568			TRAILING: DeserializeOwned,
569            ERR: Into<Error> + 'static
570		> WrapMeta<BASE, META> for fn(&BASE, META, $($x,)+ Trailing<TRAILING>) -> BoxFuture<OUT, ERR> {
571			fn wrap_rpc(&self, base: &BASE, params: Params, meta: META) -> BoxFuture<Value, Error> {
572				let len = match require_len(&params, $num) {
573					Ok(len) => len,
574					Err(e) => return futures::failed(e).boxed(),
575				};
576
577				let params = match len - $num {
578					0 => params.parse::<($($x,)+)>()
579						.map(|($($x,)+)| ($($x,)+ None)).map_err(Into::into),
580					1 => params.parse::<($($x,)+ TRAILING)>()
581						.map(|($($x,)+ id)| ($($x,)+ Some(id))).map_err(Into::into),
582					_ => Err(invalid_params(&format!("Expected {} or {} parameters.", $num, $num + 1), format!("Got: {}", len))),
583				};
584
585				match params {
586					Ok(($($x,)+ id)) => (self)(base, meta, $($x,)+ Trailing(id)).map(to_value).map_err(Into::into).boxed(),
587					Err(e) => futures::failed(e).boxed(),
588				}
589			}
590		}
591
592		// subscribe implementation
593		impl <
594			BASE: Send + Sync + 'static,
595			META: PubSubMetadata,
596			OUT: Serialize,
597			$($x: DeserializeOwned,)+
598			TRAILING: DeserializeOwned,
599		> WrapSubscribe<BASE, META> for fn(&BASE, META, pubsub::Subscriber<OUT>, $($x,)+ Trailing<TRAILING>) {
600			fn wrap_rpc(&self, base: &BASE, params: Params, meta: META, subscriber: Subscriber) {
601				let len = match require_len(&params, $num) {
602					Ok(len) => len,
603					Err(e) => {
604						let _ = subscriber.reject(e);
605						return;
606					},
607				};
608
609				let params = match len - $num {
610					0 => params.parse::<($($x,)+)>()
611						.map(|($($x,)+)| ($($x,)+ None)),
612					1 => params.parse::<($($x,)+ TRAILING)>()
613						.map(|($($x,)+ id)| ($($x,)+ Some(id))),
614					_ => {
615						let _ = subscriber.reject(invalid_params(&format!("Expected {} or {} parameters.", $num, $num + 1), format!("Got: {}", len)));
616						return;
617					},
618				};
619
620				match params {
621					Ok(($($x,)+ id)) => (self)(base, meta, pubsub::Subscriber::new(subscriber), $($x,)+ Trailing(id)),
622					Err(e) => {
623						let _ = subscriber.reject(e);
624						return;
625					},
626				}
627			}
628		}
629	}
630}
631
632wrap!(A, B, C, D, E, F);
633wrap!(A, B, C, D, E);
634wrap!(A, B, C, D);
635wrap!(A, B, C);
636wrap!(A, B);
637wrap!(A);
638
639wrap_with_trailing!(6, A, B, C, D, E, F);
640wrap_with_trailing!(5, A, B, C, D, E);
641wrap_with_trailing!(4, A, B, C, D);
642wrap_with_trailing!(3, A, B, C);
643wrap_with_trailing!(2, A, B);
644wrap_with_trailing!(1, A);
645