@@ -2,12 +2,13 @@ use crate::ast::{Handler, Object, Service, ServiceInner, ServiceType, Workflow};
22use proc_macro2:: TokenStream as TokenStream2 ;
33use proc_macro2:: { Ident , Literal } ;
44use quote:: { format_ident, quote, ToTokens } ;
5- use syn:: { parse_quote , Attribute , ReturnType , Type , Visibility } ;
5+ use syn:: { Attribute , PatType , Visibility } ;
66
77pub ( crate ) struct ServiceGenerator < ' a > {
88 pub ( crate ) service_ty : ServiceType ,
99 pub ( crate ) restate_name : & ' a str ,
1010 pub ( crate ) service_ident : & ' a Ident ,
11+ pub ( crate ) client_ident : Ident ,
1112 pub ( crate ) serve_ident : Ident ,
1213 pub ( crate ) vis : & ' a Visibility ,
1314 pub ( crate ) attrs : & ' a [ Attribute ] ,
@@ -20,6 +21,7 @@ impl<'a> ServiceGenerator<'a> {
2021 service_ty,
2122 restate_name : & s. restate_name ,
2223 service_ident : & s. ident ,
24+ client_ident : format_ident ! ( "{}Client" , s. ident) ,
2325 serve_ident : format_ident ! ( "Serve{}" , s. ident) ,
2426 vis : & s. vis ,
2527 attrs : & s. attrs ,
@@ -50,8 +52,6 @@ impl<'a> ServiceGenerator<'a> {
5052 ..
5153 } = self ;
5254
53- let unit_type: & Type = & parse_quote ! ( ( ) ) ;
54-
5555 let handler_fns = handlers
5656 . iter ( )
5757 . map (
@@ -66,13 +66,9 @@ impl<'a> ServiceGenerator<'a> {
6666 ( ServiceType :: Workflow , false ) => quote ! { :: restate_sdk:: prelude:: WorkflowContext } ,
6767 } ;
6868
69- let output = match output {
70- ReturnType :: Type ( _, ref ty) => ty. as_ref ( ) ,
71- ReturnType :: Default => unit_type,
72- } ;
7369 quote ! {
7470 #( #attrs ) *
75- fn #ident( & self , context: #ctx, #( #args ) , * ) -> impl std:: future:: Future <Output =#output> + :: core:: marker:: Send ;
71+ fn #ident( & self , context: #ctx, #( #args ) , * ) -> impl std:: future:: Future <Output =:: restate_sdk :: prelude :: HandlerResult < #output> > + :: core:: marker:: Send ;
7672 }
7773 } ,
7874 ) ;
@@ -223,6 +219,123 @@ impl<'a> ServiceGenerator<'a> {
223219 }
224220 }
225221 }
222+
223+ fn struct_client ( & self ) -> TokenStream2 {
224+ let & Self {
225+ vis,
226+ ref client_ident,
227+ // service_ident,
228+ ref service_ty,
229+ ..
230+ } = self ;
231+
232+ let key_field = match service_ty {
233+ ServiceType :: Service => quote ! { } ,
234+ ServiceType :: Object | ServiceType :: Workflow => quote ! {
235+ key: String ,
236+ } ,
237+ } ;
238+
239+ let into_client_impl = match service_ty {
240+ ServiceType :: Service => {
241+ quote ! {
242+ impl <' ctx> :: restate_sdk:: context:: IntoServiceClient <' ctx> for #client_ident<' ctx> {
243+ fn create_client( ctx: & ' ctx :: restate_sdk:: endpoint:: ContextInternal ) -> Self {
244+ Self { ctx }
245+ }
246+ }
247+ }
248+ }
249+ ServiceType :: Object => quote ! {
250+ impl <' ctx> :: restate_sdk:: context:: IntoObjectClient <' ctx> for #client_ident<' ctx> {
251+ fn create_client( ctx: & ' ctx :: restate_sdk:: endpoint:: ContextInternal , key: String ) -> Self {
252+ Self { ctx, key }
253+ }
254+ }
255+ } ,
256+ ServiceType :: Workflow => quote ! {
257+ impl <' ctx> :: restate_sdk:: context:: IntoWorkflowClient <' ctx> for #client_ident<' ctx> {
258+ fn create_client( ctx: & ' ctx :: restate_sdk:: endpoint:: ContextInternal , key: String ) -> Self {
259+ Self { ctx, key }
260+ }
261+ }
262+ } ,
263+ } ;
264+
265+ quote ! {
266+ /// Struct exposing the client to invoke [#service_ident] from another service.
267+ #vis struct #client_ident<' ctx> {
268+ ctx: & ' ctx :: restate_sdk:: endpoint:: ContextInternal ,
269+ #key_field
270+ }
271+
272+ #into_client_impl
273+ }
274+ }
275+
276+ fn impl_client ( & self ) -> TokenStream2 {
277+ let & Self {
278+ vis,
279+ ref client_ident,
280+ service_ident,
281+ handlers,
282+ restate_name,
283+ service_ty,
284+ ..
285+ } = self ;
286+
287+ let service_literal = Literal :: string ( restate_name) ;
288+
289+ let handlers_fns = handlers. iter ( ) . map ( |handler| {
290+ let handler_ident = & handler. ident ;
291+ let handler_literal = Literal :: string ( & handler. restate_name ) ;
292+
293+ let argument = match & handler. arg {
294+ None => quote ! { } ,
295+ Some ( PatType {
296+ ty, ..
297+ } ) => quote ! { req: #ty }
298+ } ;
299+ let argument_ty = match & handler. arg {
300+ None => quote ! { ( ) } ,
301+ Some ( PatType {
302+ ty, ..
303+ } ) => quote ! { #ty }
304+ } ;
305+ let res_ty = & handler. output ;
306+ let input = match & handler. arg {
307+ None => quote ! { ( ) } ,
308+ Some ( _) => quote ! { req }
309+ } ;
310+ let request_target = match service_ty {
311+ ServiceType :: Service => quote ! {
312+ :: restate_sdk:: context:: RequestTarget :: service( #service_literal, #handler_literal)
313+ } ,
314+ ServiceType :: Object => quote ! {
315+ :: restate_sdk:: context:: RequestTarget :: object( #service_literal, & self . key, #handler_literal)
316+ } ,
317+ ServiceType :: Workflow => quote ! {
318+ :: restate_sdk:: context:: RequestTarget :: workflow( #service_literal, & self . key, #handler_literal)
319+ }
320+ } ;
321+
322+ quote ! {
323+ #vis fn #handler_ident( & self , #argument) -> :: restate_sdk:: context:: Request <' ctx, #argument_ty, #res_ty> {
324+ self . ctx. request( #request_target, #input)
325+ }
326+ }
327+ } ) ;
328+
329+ let doc_msg = format ! (
330+ "Struct exposing the client to invoke [`{service_ident}`] from another service."
331+ ) ;
332+ quote ! {
333+ #[ doc = #doc_msg]
334+ impl <' ctx> #client_ident<' ctx> {
335+ #( #handlers_fns ) *
336+ }
337+ }
338+ }
226339}
227340
228341impl < ' a > ToTokens for ServiceGenerator < ' a > {
@@ -232,6 +345,8 @@ impl<'a> ToTokens for ServiceGenerator<'a> {
232345 self . struct_serve( ) ,
233346 self . impl_service_for_serve( ) ,
234347 self . impl_discoverable( ) ,
348+ self . struct_client( ) ,
349+ self . impl_client( ) ,
235350 ] ) ;
236351 }
237352}
0 commit comments