1use super::{Method, Service};
2use crate::{generate_doc_comments, naive_snake_case, Builder};
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5
6pub fn generate<T: Service>(service: &T, config: &Builder) -> TokenStream {
11 let attributes = &config.client_attributes;
12 let service_ident = quote::format_ident!("{}Client", service.name());
13 let client_mod = quote::format_ident!("{}_client", naive_snake_case(service.name()));
14 let methods = generate_methods(service, config);
15
16 let service_doc = generate_doc_comments(service.comment());
17 let mod_attributes = attributes.for_mod(service.package());
18 let struct_attributes = attributes.for_struct(service.identifier());
19
20 quote! {
21 #(#mod_attributes)*
23 pub mod #client_mod {
24 #service_doc
25 #(#struct_attributes)*
26 #[derive(Debug)]
27 pub struct #service_ident<Client> {
28 pub client: Client,
29 }
30
31 impl<Client> #service_ident<Client>
32 where
33 Client: ::prpc::client::RequestClient
34 {
35 pub fn new(client: Client) -> Self {
36 Self { client }
37 }
38
39 #methods
40 }
41 }
42 }
43}
44
45fn generate_methods<T: Service>(service: &T, config: &Builder) -> TokenStream {
46 let mut stream = TokenStream::new();
47 for method in service.methods() {
48 let path = crate::join_path(
49 config,
50 service.package(),
51 service.identifier(),
52 method.identifier(),
53 );
54
55 stream.extend(generate_doc_comments(method.comment()));
56
57 let method = match (method.client_streaming(), method.server_streaming()) {
58 (false, false) => generate_unary(method, config, path),
59 _ => {
60 panic!("Only unary method supported");
61 }
62 };
63
64 stream.extend(method);
65 }
66
67 stream
68}
69
70fn generate_unary<T: Method>(method: &T, config: &Builder, path: String) -> TokenStream {
71 let ident = format_ident!("{}", method.name());
72 let (request, response) =
73 method.request_response_name(&config.proto_path, config.compile_well_known_types);
74
75 template_quote::quote! {
76 pub async fn #ident(
77 &self
78 #(if request.is_some())
79 {
80 , request: #request,
81 }
82 ) -> Result<#response, ::prpc::client::Error> {
83 #(if request.is_none())
84 {
85 let request = ();
86 }
87 self.client.request(#path, request).await
88 }
89 }
90}