Skip to content

Commit 36a3803

Browse files
committed
Implement server side named parameters
1 parent 17883c0 commit 36a3803

8 files changed

+62
-52
lines changed

derive/src/options.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,7 @@ impl DeriveOptions {
6262
options.enable_client = true;
6363
options.enable_server = true;
6464
}
65-
if options.enable_server && options.params_style == ParamStyle::Named {
66-
// This is not allowed at this time
67-
panic!("Server code generation only supports `params = \"positional\"` (default) or `params = \"raw\" at this time.")
68-
}
65+
6966
Ok(options)
7067
}
7168
}

derive/src/rpc_trait.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::options::DeriveOptions;
2-
use crate::params_style::ParamStyle;
32
use crate::rpc_attr::{AttributeKind, PubSubMethodKind, RpcMethodAttribute};
43
use crate::to_client::generate_client_module;
54
use crate::to_delegate::{generate_trait_item_method, MethodRegistration, RpcMethod};
@@ -22,10 +21,6 @@ const MISSING_UNSUBSCRIBE_METHOD_ERR: &str =
2221
"Can't find unsubscribe method, expected a method annotated with `unsubscribe` \
2322
e.g. `#[pubsub(subscription = \"hello\", unsubscribe, name = \"hello_unsubscribe\")]`";
2423

25-
pub const USING_NAMED_PARAMS_WITH_SERVER_ERR: &str =
26-
"`params = \"named\"` can only be used to generate a client (on a trait annotated with #[rpc(client)]). \
27-
At this time the server does not support named parameters.";
28-
2924
const RPC_MOD_NAME_PREFIX: &str = "rpc_impl_";
3025

3126
struct RpcTrait {
@@ -222,12 +217,6 @@ fn rpc_wrapper_mod_name(rpc_trait: &syn::ItemTrait) -> syn::Ident {
222217
syn::Ident::new(&mod_name, proc_macro2::Span::call_site())
223218
}
224219

225-
fn has_named_params(methods: &[RpcMethod]) -> bool {
226-
methods
227-
.iter()
228-
.any(|method| method.attr.params_style == Some(ParamStyle::Named))
229-
}
230-
231220
pub fn crate_name(name: &str) -> Result<Ident> {
232221
proc_macro_crate::crate_name(name)
233222
.map(|name| Ident::new(&name, Span::call_site()))
@@ -264,9 +253,6 @@ pub fn rpc_impl(input: syn::Item, options: &DeriveOptions) -> Result<proc_macro2
264253
});
265254
}
266255
if options.enable_server {
267-
if has_named_params(&methods) {
268-
return Err(syn::Error::new_spanned(rpc_trait, USING_NAMED_PARAMS_WITH_SERVER_ERR));
269-
}
270256
let rpc_server_module = generate_server_module(&method_registrations, &rpc_trait, &methods)?;
271257
submodules.push(rpc_server_module);
272258
exports.push(quote! {

derive/src/to_delegate.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,21 @@ impl RpcMethod {
218218
})
219219
.collect();
220220

221+
let arg_names: Vec<_> = self
222+
.trait_item
223+
.sig
224+
.inputs
225+
.iter()
226+
.cloned()
227+
.filter_map(|arg| match arg {
228+
syn::FnArg::Typed(pat) => match *pat.pat {
229+
syn::Pat::Ident(pat) => Some(pat.ident),
230+
_ => None,
231+
},
232+
_ => None,
233+
})
234+
.collect();
235+
221236
// special args are those which are not passed directly via rpc params: metadata, subscriber
222237
let special_args = Self::special_args(&param_types);
223238
param_types.retain(|ty| !special_args.iter().any(|(_, sty)| sty == ty));
@@ -246,7 +261,17 @@ impl RpcMethod {
246261
} else if self.attr.params_style == Some(ParamStyle::Positional) {
247262
quote! { let params = params.parse::<(#(#param_types, )*)>(); }
248263
} else {
249-
unimplemented!("Server side named parameters are not implemented");
264+
quote! {
265+
#[derive(serde::Deserialize)]
266+
#[allow(non_camel_case_types)]
267+
struct __Params {
268+
#(
269+
#arg_names: #param_types,
270+
)*
271+
}
272+
let params = params.parse::<__Params>()
273+
.map(|__Params { #(#arg_names, )* }| (#(#arg_names, )*));
274+
}
250275
}
251276
};
252277

derive/tests/macros.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub trait Rpc {
3030
#[rpc(name = "raw", params = "raw")]
3131
fn raw(&self, params: Params) -> Result<String>;
3232

33+
#[rpc(name = "named_add", params = "named")]
34+
fn named_add(&self, a: u64, b: u64) -> Result<u64>;
35+
3336
/// Handles a notification.
3437
#[rpc(name = "notify")]
3538
fn notify(&self, a: u64);
@@ -55,6 +58,10 @@ impl Rpc for RpcImpl {
5558
Ok("OK".into())
5659
}
5760

61+
fn named_add(&self, a: u64, b: u64) -> Result<u64> {
62+
Ok(a + b)
63+
}
64+
5865
fn notify(&self, a: u64) {
5966
println!("Received `notify` with value: {}", a);
6067
}
@@ -222,6 +229,34 @@ fn should_accept_any_raw_params() {
222229
assert_eq!(expected, result4);
223230
}
224231

232+
#[test]
233+
fn should_accept_named_params() {
234+
let mut io = IoHandler::new();
235+
let rpc = RpcImpl::default();
236+
io.extend_with(rpc.to_delegate());
237+
238+
// when
239+
let req1 = r#"{"jsonrpc":"2.0","id":1,"method":"named_add","params":{"a":1,"b":2}}"#;
240+
let req2 = r#"{"jsonrpc":"2.0","id":1,"method":"named_add","params":{"b":2,"a":1}}"#;
241+
242+
let res1 = io.handle_request_sync(req1);
243+
let res2 = io.handle_request_sync(req2);
244+
245+
let expected = r#"{
246+
"jsonrpc": "2.0",
247+
"result": 3,
248+
"id": 1
249+
}"#;
250+
let expected: Response = serde_json::from_str(expected).unwrap();
251+
252+
// then
253+
let result1: Response = serde_json::from_str(&res1.unwrap()).unwrap();
254+
assert_eq!(expected, result1);
255+
256+
let result2: Response = serde_json::from_str(&res2.unwrap()).unwrap();
257+
assert_eq!(expected, result2);
258+
}
259+
225260
#[test]
226261
fn should_accept_only_notifications() {
227262
let mut io = IoHandler::new();

derive/tests/ui/attr-named-params-on-server.rs

Lines changed: 0 additions & 10 deletions
This file was deleted.

derive/tests/ui/attr-named-params-on-server.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

derive/tests/ui/trait-attr-named-params-on-server.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

derive/tests/ui/trait-attr-named-params-on-server.stderr

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)