servant_macro/
lib.rs

1// -- lib.rs --
2
3//! servant-macro是servant库的辅助库,本库定义了四种类型的接口属性,会自动生成客户端和服务
4//! 端的代码,方便应用开发。
5//!
6//! # Features说明
7//!
8//! ### adapter
9//!
10//! 生成服务端的代码。
11//!
12//! ### terminal
13//!
14//! 生成客户端的代码
15//!
16//! ### invoke
17//!
18//! 定义invoke接口,并根据adapter/terminal属性,生成服务端和客户端代码。
19//!
20//! ### query
21//!
22//! 定义query接口,并根据adapter/terminal属性,生成服务端和客户端代码。
23//!
24//! ### report
25//!
26//! 定义report接口,并根据adapter/terminal属性,生成服务端和客户端代码。
27//!
28//! ### notify
29//!
30//! 定义notify接口,并根据adapter/terminal属性,生成服务端和客户端代码。
31
32#[macro_use]
33extern crate syn;
34#[macro_use]
35extern crate quote;
36extern crate proc_macro;
37extern crate proc_macro2;
38
39// --
40
41use proc_macro::TokenStream;
42use syn::{FnArg, Ident, ItemTrait, ReturnType, Signature, TraitItem, TraitItemMethod};
43
44// --
45
46/// 定义带返回值方法的接口,接口中可以有多个带返回值的方法。
47///
48/// 在一个应用中,可以定义多个invoke接口,客户端调用这些接口的方法,请求服务端的服务,服务端
49/// 通过方法的返回值,响应客户端的请求。
50///
51/// 在服务端会生成同名的trait,服务端要实现这个trait,在每个方法中提供服务。只有将每个实现添
52/// 加到ServantRegister中,客户端才能请求该实现的服务。
53///
54/// 在客户端会生成后缀Proxy的struct,自动实现了该trait的方法,可以通过Terminal的proxy方
55/// 法,生成这个proxy,调用接口的方法,向服务端请求服务。
56///
57/// # Notice
58/// 接口中方法的第一个参数必须是&self或&mut self,因为接口在服务端都是按照对象提供服务的,每个接口
59/// 可以有不同的实现类,每个类也可以有不同名字的对象分别提供服务。
60///
61/// # Example
62/// ```
63/// #[servant::invoke_interface]
64/// pub trait Dog: Clone {
65///     fn speak(&self, count: i32) -> String;
66///     fn owner(&self) -> servant::Oid;
67///     fn age(&mut self, i: u32) -> u32;
68/// }
69/// ```
70#[cfg(feature = "invoke")]
71#[proc_macro_attribute]
72pub fn invoke_interface(_attr: TokenStream, input: TokenStream) -> TokenStream {
73    // let derive_serde = parse_macro_input!(attr as DeriveSerde);
74    let ItemTrait {
75        attrs,
76        vis,
77        unsafety,
78        auto_token,
79        trait_token,
80        ident,
81        generics,
82        colon_token,
83        supertraits,
84        // brace_token,
85        items,
86        ..
87    } = parse_macro_input!(input as ItemTrait);
88
89    let methods: Vec<TraitItemMethod> = items
90        .iter()
91        .map(|i| {
92            if let TraitItem::Method(m) = i {
93                Some(m)
94            } else {
95                None
96            }
97        })
98        .filter(|i| i.is_some())
99        .map(|x| x.unwrap().clone())
100        .collect();
101    let idents_collected: Vec<_> = methods
102        .iter()
103        .map(|x| {
104            let TraitItemMethod {
105                attrs,
106                sig,
107                default,
108                semi_token,
109            } = x;
110            let Signature {
111                constness,
112                asyncness,
113                unsafety,
114                abi,
115                fn_token,
116                ident,
117                generics,
118                // paren_token,
119                inputs,
120                variadic,
121                output,
122                ..
123            } = sig;
124
125            let output_type = match output.clone() {
126                ReturnType::Default => quote! {()},
127                ReturnType::Type(_, t) => quote! {#t},
128            };
129            let ident_camel = Ident::new(&snake_to_camel(&ident.to_string()), ident.span());
130            let args: Vec<_> = inputs
131                .iter()
132                .map(|i| {
133                    if let FnArg::Typed(pat) = i {
134                        Some(pat)
135                    } else {
136                        None
137                    }
138                })
139                .filter(|i| i.is_some())
140                .map(|x| {
141                    let x = &x.unwrap().pat;
142                    quote! {#x,}
143                })
144                .collect();
145            let input_receiver: Vec<_> = inputs
146                .iter()
147                .map(|i| {
148                    if let FnArg::Receiver(receiver) = i {
149                        Some(receiver)
150                    } else {
151                        None
152                    }
153                })
154                .filter(|i| i.is_some())
155                .map(|x| {
156                    let x = x.unwrap();
157                    quote! {#x,}
158                })
159                .collect();
160            let inputs: Vec<_> = inputs
161                .iter()
162                .map(|i| {
163                    if let FnArg::Typed(pat) = i {
164                        Some(pat)
165                    } else {
166                        None
167                    }
168                })
169                .filter(|i| i.is_some())
170                .map(|x| {
171                    let x = x.unwrap();
172                    quote! {#x,}
173                })
174                .collect();
175            let method = quote! {
176                #(#attrs)*
177                #constness #asyncness #unsafety #abi #fn_token #ident #generics (
178                    #(#input_receiver)* ctx: Option<servant::Context>,
179                    #(#inputs)* #variadic
180                ) #output
181                #default #semi_token
182            };
183            (ident, ident_camel, args, inputs, method, output_type)
184        })
185        .collect();
186    let ident_vec: Vec<_> = idents_collected.iter().map(|i| i.0.clone()).collect();
187    let idents_camel_vec: Vec<_> = idents_collected.iter().map(|i| i.1.clone()).collect();
188    let args_vec: Vec<_> = idents_collected.iter().map(|i| i.2.clone()).collect();
189    let inputs_vec: Vec<_> = idents_collected.iter().map(|i| i.3.clone()).collect();
190    let methods_vec: Vec<_> = idents_collected.iter().map(|i| i.4.clone()).collect();
191    let output_vec: Vec<_> = idents_collected.iter().map(|i| i.5.clone()).collect();
192
193    let request_ident = Ident::new(&format!("{}Request", ident), ident.span());
194    let request_ident_vect: Vec<_> = idents_collected
195        .iter()
196        .map(|_| request_ident.clone())
197        .collect();
198    let servant_ident = Ident::new(&format!("{}Servant", ident), ident.span());
199    let proxy_ident = Ident::new(&format!("{}Proxy", ident), ident.span());
200
201    let output1 = if cfg!(any(feature = "adapter", feature = "terminal")) { quote! {
202        #[derive(serde::Serialize, serde::Deserialize)]
203        enum #request_ident {
204            #(#idents_camel_vec { #(#inputs_vec)* },)*
205        }}
206    } else {
207        proc_macro2::TokenStream::new()
208    };
209    let output2 = if cfg!(feature = "adapter") { quote! {
210        #( #attrs )*
211        #vis #unsafety #auto_token #trait_token #ident #generics #colon_token #supertraits {
212            #(#methods_vec)*
213        }
214        pub struct #servant_ident<S> {
215            name: String,
216            entity: S,
217        }
218        impl<S> #servant_ident<S> {
219            pub fn new(name: &str, entity: S) -> Self {
220                Self { name: name.to_string(), entity }
221            }
222        }
223        impl<S> servant::Servant for #servant_ident<S>
224        where
225            S: #ident + 'static,
226        {
227            fn name(&self) -> &str {
228                &self.name
229            }
230            fn category(&self) -> &'static str {
231                stringify!(#ident)
232            }
233            fn serve(&mut self, ctx: Option<servant::Context>, req: Vec<u8>) -> Vec<u8> {
234                let req: #request_ident = bincode::deserialize(&req).unwrap();
235                let reps = match req {
236                    #(
237                        #request_ident_vect::#idents_camel_vec{ #(#args_vec)* } =>
238                            bincode::serialize(&self.entity.#ident_vec(ctx, #(#args_vec)*)),
239                    )*
240                }
241                .unwrap();
242                reps
243            }
244        }}
245    } else {
246        proc_macro2::TokenStream::new()
247    };
248
249    let output3 = if cfg!(feature = "terminal") { quote!{
250        #[derive(Clone)]
251        pub struct #proxy_ident(servant::Context, servant::Oid, servant::Terminal);
252
253        impl #proxy_ident {
254            pub fn new(ctx: servant::Context, name: &str, t: &servant::Terminal) -> Self {
255                let oid = servant::Oid::new(name, stringify!(#ident));
256                Self(ctx, oid, t.clone())
257            }
258
259            #(
260            pub async fn #ident_vec(
261                &mut self,
262                #(#inputs_vec)*
263            ) -> servant::ServantResult<#output_vec> {
264                let request =  #request_ident_vect::#idents_camel_vec { #(#args_vec)* };
265                let response = self
266                    .2
267                    .invoke(Some(self.0.clone()), Some(self.1.clone()), bincode::serialize(&request).unwrap())
268                    .await;
269                response.map(|x| bincode::deserialize(&x).unwrap())
270            }
271            )*
272        }}
273    } else {
274        proc_macro2::TokenStream::new()
275    };
276
277    let output = quote! {
278        #output1
279        #output2
280        #output3
281    };
282    output.into()
283}
284
285/// 定义不带返回值方法的接口,接口中可以有多个不带返回值的方法。
286///
287/// report接口是单向的,只能从客户端上报到服务端。
288///
289/// 在一个应用中,可以定义多个report接口,客户端调用这些接口的方法,向服务端发送报告,服务端
290/// 通在实现接口的类中,使用这些报告信息。
291///
292/// 在服务端会生成同名的trait,服务端要实现这个trait,在每个方法中接收和处理客户端上报的信息。
293/// 只有将每个实现添加到ServantRegister中,才能接收并处理客户端上报的信息。
294///
295/// 在客户端会生成后缀Proxy的struct,自动实现了该trait的方法,可以通过Terminal的proxy方
296/// 法,生成这个proxy,调用接口的方法,向服务端请求服务。
297///
298/// # Notice
299/// 接口中方法的第一个参数必须是&self或&mut self,因为接口在服务端都是按照对象提供服务的,每个接口
300/// 可以有不同的实现类,每个类也可以有不同名字的对象分别提供服务。
301///
302/// # Example
303/// ```
304/// #[servant::report_interface]
305/// pub trait Pusher {
306///     fn f1(&self, count: i32);
307///     fn f2(&self);
308///     fn f3(&mut self, s: String);
309/// }
310/// ```
311#[cfg(feature = "report")]
312#[proc_macro_attribute]
313pub fn report_interface(_attr: TokenStream, input: TokenStream) -> TokenStream {
314    let ItemTrait {
315        attrs,
316        vis,
317        unsafety,
318        auto_token,
319        trait_token,
320        ident,
321        generics,
322        colon_token,
323        supertraits,
324        // brace_token,
325        items,
326        ..
327    } = parse_macro_input!(input as ItemTrait);
328
329    let methods: Vec<TraitItemMethod> = items
330        .iter()
331        .map(|i| {
332            if let TraitItem::Method(m) = i {
333                Some(m)
334            } else {
335                None
336            }
337        })
338        .filter(|i| i.is_some())
339        .map(|x| x.unwrap().clone())
340        .collect();
341    let idents_collected: Vec<_> = methods
342        .iter()
343        .map(|x| {
344            let TraitItemMethod {
345                attrs,
346                sig,
347                default,
348                semi_token,
349            } = x;
350            let Signature {
351                constness,
352                asyncness,
353                unsafety,
354                abi,
355                fn_token,
356                ident,
357                generics,
358                // paren_token,
359                inputs,
360                variadic,
361                // output,
362                ..
363            } = sig;
364
365            let ident_camel = Ident::new(&snake_to_camel(&ident.to_string()), ident.span());
366            let args: Vec<_> = inputs
367                .iter()
368                .map(|i| {
369                    if let FnArg::Typed(pat) = i {
370                        Some(pat)
371                    } else {
372                        None
373                    }
374                })
375                .filter(|i| i.is_some())
376                .map(|x| {
377                    let x = &x.unwrap().pat;
378                    quote! {#x,}
379                })
380                .collect();
381            let inputs2: Vec<_> = inputs
382                .iter()
383                .map(|i| {
384                    if let FnArg::Typed(pat) = i {
385                        Some(pat)
386                    } else {
387                        None
388                    }
389                })
390                .filter(|i| i.is_some())
391                .map(|x| {
392                    let x = x.unwrap();
393                    quote! {#x,}
394                })
395                .collect();
396            let servant_method = quote! {
397                #(#attrs)*
398                #constness #asyncness #unsafety #abi #fn_token #ident #generics (
399                    #inputs #variadic
400                )
401                #default #semi_token
402            };
403            (ident, ident_camel, args, inputs2, servant_method)
404        })
405        .collect();
406    let ident_vec: Vec<_> = idents_collected.iter().map(|i| i.0.clone()).collect();
407    let idents_camel_vec: Vec<_> = idents_collected.iter().map(|i| i.1.clone()).collect();
408    let args_vec: Vec<_> = idents_collected.iter().map(|i| i.2.clone()).collect();
409    let inputs_vec: Vec<_> = idents_collected.iter().map(|i| i.3.clone()).collect();
410    let methods_vec: Vec<_> = idents_collected.iter().map(|i| i.4.clone()).collect();
411
412    let request_ident = Ident::new(&format!("{}Request", ident), ident.span());
413    let request_ident_vect: Vec<_> = idents_collected
414        .iter()
415        .map(|_| request_ident.clone())
416        .collect();
417    let servant_ident = Ident::new(&format!("{}ReportServant", ident), ident.span());
418    let proxy_ident = Ident::new(&format!("{}ReportProxy", ident), ident.span());
419
420    let output1 = if cfg!(any(feature = "adapter", feature = "terminal")) { quote! {
421        #[derive(serde::Serialize, serde::Deserialize)]
422        enum #request_ident {
423            #(#idents_camel_vec { #(#inputs_vec)* },)*
424        }}
425    } else {
426        proc_macro2::TokenStream::new()
427    };
428    let output2 = if cfg!(feature = "adapter") { quote! {
429        #( #attrs )*
430        #vis #unsafety #auto_token #trait_token #ident #generics #colon_token #supertraits {
431            #(#methods_vec)*
432        }
433        pub struct #servant_ident<S> {
434            name: String,
435            entity: S,
436        }
437        impl<S> #servant_ident<S> {
438            pub fn new(name: &str, entity: S) -> Self {
439                Self { name: name.to_string(), entity }
440            }
441        }
442        impl<S> servant::ReportServant for #servant_ident<S>
443        where
444            S: #ident + 'static,
445        {
446            fn name(&self) -> &str {
447                &self.name
448            }
449            fn category(&self) -> &'static str {
450                stringify!(#ident)
451            }
452            fn serve(&mut self, req: Vec<u8>) {
453                let req: #request_ident = bincode::deserialize(&req).unwrap();
454                match req {
455                    #(
456                        #request_ident_vect::#idents_camel_vec{ #(#args_vec)* } =>
457                            self.entity.#ident_vec(#(#args_vec)*),
458                    )*
459                }
460            }
461        }}
462    } else {
463        proc_macro2::TokenStream::new()
464    };
465    let output3 = if cfg!(feature = "terminal") { quote!{
466        #[derive(Clone)]
467        pub struct #proxy_ident(servant::Oid, servant::Terminal);
468
469        impl #proxy_ident {
470            pub fn new(name: &str, t: &servant::Terminal) -> Self {
471                let oid = servant::Oid::new(name, stringify!(#ident));
472                Self(oid, t.clone())
473            }
474
475            #(
476            #[allow(unused)]
477            pub async fn #ident_vec(
478                &mut self,
479                #(#inputs_vec)*
480            ) -> servant::ServantResult<()> {
481                let request =  #request_ident_vect::#idents_camel_vec { #(#args_vec)* };
482                let response = self
483                    .1
484                    .report(self.0.clone(), bincode::serialize(&request).unwrap())
485                    .await;
486                response
487            }
488            )*
489        }}
490    } else {
491        proc_macro2::TokenStream::new()
492    };
493
494    let output = quote! {
495        #output1
496        #output2
497        #output3
498    };
499    output.into()
500}
501
502/// 定义query接口,query接口实际上就是一个invoke接口。
503///
504/// 在一个应用中,只可以有一个query接口。这个query接口向客户端提供本服务端的基本信息,比如,
505/// 有那些提供服务的对象,有哪些接收报告的对象。
506///
507/// 在服务端会生成同名的trait,服务端要实现这个trait,在每个方法中提供服务。只有将每个实现添
508/// 加到ServantRegister中,客户端才能请求该实现的服务。
509///
510/// 在客户端会生成后缀Proxy的struct,自动实现了该trait的方法,可以通过Terminal的proxy方
511/// 法,生成这个proxy,调用接口的方法,向服务端请求服务。
512///
513/// 在servant中,缺省实现的query接口是Export,方便客户端查询服务端的信息。
514///
515/// 实际应用中,开发者可以定义自己的query接口。
516///
517/// # Notice
518/// 接口中方法的第一个参数必须是&self或&mut self,因为接口在服务端都是按照对象提供服务的。
519///
520/// # Example
521/// ```
522/// #[servant_macro::query_interface]
523/// pub trait Export {
524///     fn export_servants(&self) -> Vec<Oid>;
525///     fn export_report_servants(&self) -> Vec<Oid>;
526///     fn shutdown(&self, passcode: usize);
527/// }
528/// ```
529#[cfg(feature = "query")]
530#[proc_macro_attribute]
531pub fn query_interface(_attr: TokenStream, input: TokenStream) -> TokenStream {
532    let ItemTrait {
533        attrs,
534        vis,
535        unsafety,
536        auto_token,
537        trait_token,
538        ident,
539        generics,
540        colon_token,
541        supertraits,
542        // brace_token,
543        items,
544        ..
545    } = parse_macro_input!(input as ItemTrait);
546
547    let methods: Vec<TraitItemMethod> = items
548        .iter()
549        .map(|i| {
550            if let TraitItem::Method(m) = i {
551                Some(m)
552            } else {
553                None
554            }
555        })
556        .filter(|i| i.is_some())
557        .map(|x| x.unwrap().clone())
558        .collect();
559    let idents_collected: Vec<_> = methods
560        .iter()
561        .map(|x| {
562            let TraitItemMethod {
563                attrs,
564                sig,
565                default,
566                semi_token,
567            } = x;
568            let Signature {
569                constness,
570                asyncness,
571                unsafety,
572                abi,
573                fn_token,
574                ident,
575                generics,
576                // paren_token,
577                inputs,
578                variadic,
579                output,
580                ..
581            } = sig;
582
583            let output_type = match output.clone() {
584                ReturnType::Default => quote! {()},
585                ReturnType::Type(_, t) => quote! {#t},
586            };
587            let ident_camel = Ident::new(&snake_to_camel(&ident.to_string()), ident.span());
588            let args: Vec<_> = inputs
589                .iter()
590                .map(|i| {
591                    if let FnArg::Typed(pat) = i {
592                        Some(pat)
593                    } else {
594                        None
595                    }
596                })
597                .filter(|i| i.is_some())
598                .map(|x| {
599                    let x = &x.unwrap().pat;
600                    quote! {#x,}
601                })
602                .collect();
603            let inputs: Vec<_> = inputs
604                .iter()
605                .map(|i| {
606                    if let FnArg::Typed(pat) = i {
607                        Some(pat)
608                    } else {
609                        None
610                    }
611                })
612                .filter(|i| i.is_some())
613                .map(|x| {
614                    let x = x.unwrap();
615                    quote! {#x,}
616                })
617                .collect();
618            let method = quote! {
619                #(#attrs)*
620                #constness #asyncness #unsafety #abi #fn_token #ident #generics (
621                    &mut self,
622                    #(#inputs)* #variadic
623                ) #output
624                #default #semi_token
625            };
626            (ident, ident_camel, args, inputs, method, output_type)
627        })
628        .collect();
629    let ident_vec: Vec<_> = idents_collected.iter().map(|i| i.0.clone()).collect();
630    let idents_camel_vec: Vec<_> = idents_collected.iter().map(|i| i.1.clone()).collect();
631    let args_vec: Vec<_> = idents_collected.iter().map(|i| i.2.clone()).collect();
632    let inputs_vec: Vec<_> = idents_collected.iter().map(|i| i.3.clone()).collect();
633    let _methods_vec: Vec<_> = idents_collected.iter().map(|i| i.4.clone()).collect();
634    let output_vec: Vec<_> = idents_collected.iter().map(|i| i.5.clone()).collect();
635
636    let request_ident = Ident::new(&format!("{}Request", ident), ident.span());
637    let request_ident_vect: Vec<_> = idents_collected
638        .iter()
639        .map(|_| request_ident.clone())
640        .collect();
641    let servant_ident = Ident::new(&format!("{}Servant", ident), ident.span());
642    let proxy_ident = Ident::new(&format!("{}Proxy", ident), ident.span());
643
644    let output1 = if cfg!(any(feature = "adapter", feature = "terminal")) { quote! {
645        #[derive(serde::Serialize, serde::Deserialize)]
646        enum #request_ident {
647            #(#idents_camel_vec { #(#inputs_vec)* },)*
648        }}
649    } else {
650        proc_macro2::TokenStream::new()
651    };
652    let output2 = if cfg!(feature = "adapter") { quote! {
653        #( #attrs )*
654        #vis #unsafety #auto_token #trait_token #ident #generics #colon_token #supertraits {
655            #(#methods)*
656        }
657        pub struct #servant_ident<S> {
658            entity: S,
659        }
660        impl<S> #servant_ident<S> {
661            pub fn new(entity: S) -> Self {
662                Self { entity }
663            }
664        }
665        impl<S> servant::Servant for #servant_ident<S>
666        where
667            S: #ident + 'static,
668        {
669            fn name(&self) -> &str {
670                ""
671            }
672            fn category(&self) -> &'static str {
673                stringify!(#ident)
674            }
675            fn serve(&mut self, _ctx: Option<servant::Context>, req: Vec<u8>) -> Vec<u8> {
676                let req: #request_ident = bincode::deserialize(&req).unwrap();
677                let reps = match req {
678                    #(
679                        #request_ident_vect::#idents_camel_vec{ #(#args_vec)* } =>
680                            bincode::serialize(&self.entity.#ident_vec(#(#args_vec)*)),
681                    )*
682                }
683                .unwrap();
684                reps
685            }
686        }}
687    } else {
688        proc_macro2::TokenStream::new()
689    };
690    let output3 = if cfg!(feature = "terminal") { quote!{
691        #[derive(Clone)]
692        pub struct #proxy_ident(servant::Terminal);
693
694        impl #proxy_ident {
695            pub fn new(t: &servant::Terminal) -> Self {
696                Self(t.clone())
697            }
698
699            #(
700            pub async fn #ident_vec(
701                &mut self,
702                #(#inputs_vec)*
703            ) -> servant::ServantResult<#output_vec> {
704                let request =  #request_ident_vect::#idents_camel_vec { #(#args_vec)* };
705                let response = self
706                    .0
707                    .invoke(None, None, bincode::serialize(&request).unwrap())
708                    .await;
709                response.map(|x| bincode::deserialize(&x).unwrap())
710            }
711            )*
712        }}
713    } else {
714        proc_macro2::TokenStream::new()
715    };
716
717    let output = quote! {
718        #output1
719        #output2
720        #output3
721    };
722    output.into()
723}
724
725
726/// 定义notify接口,notify接口中的方法不能有返回值。
727///
728/// notify接口是单向的,只是用来从服务器向每个连接的客户端发送通知。
729///
730/// 在一个应用中,只可以有一个notify接口。这个notify接口向客户端发布信息,比如,状态改变或定
731/// 时性的通知信息。客户端在实现notify接口的ServantEntry中,接收并处理服务端的通知信息。
732///
733/// 在客户端会生成同名的trait,客户端要实现这个trait,在每个方法中接收并处理来自服务端的通知。
734/// 只有将该实现添加到Terminal中,客户端才能收到并处理服务器端的通知。
735///
736/// 在服务端会生成后缀Notifier的struct,自动实现了该trait的方法。在服务端调用该struct的
737/// instance()关联方法,得到该struct的一个引用,调用该引用的接口,向客户端发送通知。
738///
739/// # Notice
740/// 接口中方法的第一个参数必须是&self或&mut self,因为接口在服务端都是按照对象提供服务的。
741///
742/// # Example
743/// ```
744/// #[servant::notify_interface]
745/// pub trait StockNews {
746///     fn f1(&self, count: i32);
747///     fn f2(&self, msg: String);
748///     fn f3(&mut self, count: usize, f: f64, b: Option<bool>, s: Vec<String>);
749/// }
750/// ```
751#[cfg(feature = "notify")]
752#[proc_macro_attribute]
753pub fn notify_interface(_attr: TokenStream, input: TokenStream) -> TokenStream {
754    let ItemTrait {
755        attrs,
756        vis,
757        unsafety,
758        auto_token,
759        trait_token,
760        ident,
761        generics,
762        colon_token,
763        supertraits,
764        // brace_token,
765        items,
766        ..
767    } = parse_macro_input!(input as ItemTrait);
768
769    let methods: Vec<TraitItemMethod> = items
770        .iter()
771        .map(|i| {
772            if let TraitItem::Method(m) = i {
773                Some(m)
774            } else {
775                None
776            }
777        })
778        .filter(|i| i.is_some())
779        .map(|x| x.unwrap().clone())
780        .collect();
781    let idents_collected: Vec<_> = methods
782        .iter()
783        .map(|x| {
784            let TraitItemMethod {
785                attrs,
786                sig,
787                default,
788                semi_token,
789            } = x;
790            let Signature {
791                constness,
792                asyncness,
793                unsafety,
794                abi,
795                fn_token,
796                ident,
797                generics,
798                // paren_token,
799                inputs,
800                variadic,
801                // output,
802                ..
803            } = sig;
804
805            let ident_camel = Ident::new(&snake_to_camel(&ident.to_string()), ident.span());
806            let args: Vec<_> = inputs
807                .iter()
808                .map(|i| {
809                    if let FnArg::Typed(pat) = i {
810                        Some(pat)
811                    } else {
812                        None
813                    }
814                })
815                .filter(|i| i.is_some())
816                .map(|x| {
817                    let x = &x.unwrap().pat;
818                    quote! {#x,}
819                })
820                .collect();
821            let inputs2: Vec<_> = inputs
822                .iter()
823                .map(|i| {
824                    if let FnArg::Typed(pat) = i {
825                        Some(pat)
826                    } else {
827                        None
828                    }
829                })
830                .filter(|i| i.is_some())
831                .map(|x| {
832                    let x = x.unwrap();
833                    quote! {#x,}
834                })
835                .collect();
836            let servant_method = quote! {
837                #(#attrs)*
838                #constness #asyncness #unsafety #abi #fn_token #ident #generics (
839                    #inputs #variadic
840                )
841                #default #semi_token
842            };
843            (ident, ident_camel, args, inputs2, servant_method)
844        })
845        .collect();
846    let ident_vec: Vec<_> = idents_collected.iter().map(|i| i.0.clone()).collect();
847    let idents_camel_vec: Vec<_> = idents_collected.iter().map(|i| i.1.clone()).collect();
848    let args_vec: Vec<_> = idents_collected.iter().map(|i| i.2.clone()).collect();
849    let inputs_vec: Vec<_> = idents_collected.iter().map(|i| i.3.clone()).collect();
850    let methods_vec: Vec<_> = idents_collected.iter().map(|i| i.4.clone()).collect();
851
852    let request_ident = Ident::new(&format!("{}Request", ident), ident.span());
853    let request_ident_vect: Vec<_> = idents_collected
854        .iter()
855        .map(|_| request_ident.clone())
856        .collect();
857    let receiver_ident = Ident::new(&format!("{}Receiver", ident), ident.span());
858    let notifier_ident = Ident::new(&format!("{}Notifier", ident), ident.span());
859
860    let output1 = if cfg!(any(feature = "adapter", feature = "terminal")) { quote! {
861        #[derive(serde::Serialize, serde::Deserialize)]
862        enum #request_ident {
863            #(#idents_camel_vec { #(#inputs_vec)* },)*
864        }}
865    } else {
866        proc_macro2::TokenStream::new()
867    };
868    let output2 = if cfg!(feature = "terminal") { quote! {
869        #( #attrs )*
870        #vis #unsafety #auto_token #trait_token #ident #generics #colon_token #supertraits {
871            #(#methods_vec)*
872        }
873        pub struct #receiver_ident<S> {
874            entity: S,
875        }
876        impl<S> #receiver_ident<S> {
877            pub fn new(entity: S) -> Self {
878                Self { entity }
879            }
880        }
881        impl<S> servant::NotifyServant for #receiver_ident<S>
882        where
883            S: #ident + 'static + Send,
884        {
885            fn serve(&mut self, req: Vec<u8>) {
886                let req: #request_ident = bincode::deserialize(&req).unwrap();
887                match req {
888                    #(
889                        #request_ident_vect::#idents_camel_vec{ #(#args_vec)* } =>
890                            self.entity.#ident_vec(#(#args_vec)*),
891                    )*
892                }
893            }
894        }}
895    } else {
896        proc_macro2::TokenStream::new()
897    };
898    let output3 = if cfg!(feature = "adapter") { quote!{
899        pub struct #notifier_ident(&'static servant::AdapterRegister);
900
901        impl #notifier_ident {
902            pub fn instance() -> &'static #notifier_ident {
903                static mut NOTIFIER: Option<#notifier_ident> = None;
904                static INIT: std::sync::Once = std::sync::Once::new();
905
906                unsafe {
907                    INIT.call_once(|| {
908                        NOTIFIER = Some(#notifier_ident(servant::AdapterRegister::instance()));
909                    });
910                    NOTIFIER.as_ref().unwrap()
911                }
912            }
913
914            #(
915            pub async fn #ident_vec(
916                &self,
917                #(#inputs_vec)*
918            )  {
919                let request =  #request_ident_vect::#idents_camel_vec { #(#args_vec)* };
920                self
921                    .0
922                    .send(bincode::serialize(&request).unwrap())
923                    .await
924            }
925            )*
926        }}
927    } else {
928        proc_macro2::TokenStream::new()
929    };
930
931    let output = quote! {
932        #output1
933        #output2
934        #output3
935    };
936    output.into()
937}
938
939// --
940
941fn snake_to_camel(ident_str: &str) -> String {
942    let mut camel_ty = String::new();
943    let chars = ident_str.chars();
944
945    let mut last_char_was_underscore = true;
946    for c in chars {
947        match c {
948            '_' => last_char_was_underscore = true,
949            c if last_char_was_underscore => {
950                camel_ty.extend(c.to_uppercase());
951                last_char_was_underscore = false;
952            }
953            c => camel_ty.extend(c.to_lowercase()),
954        }
955    }
956
957    camel_ty
958}
959
960#[allow(unused)]
961fn snake_to_camel2(ident_str: &str) -> String {
962    let mut camel_ty = String::new();
963    let chars = ident_str.chars();
964
965    let mut last_char_was_underscore = true;
966    for c in chars {
967        match c {
968            '_' => last_char_was_underscore = true,
969            c => camel_ty.push_str(&if last_char_was_underscore {
970                last_char_was_underscore = false;
971                c.to_uppercase().to_string()
972            } else {
973                c.to_lowercase().to_string()
974            }),
975        }
976    }
977
978    camel_ty
979}
980
981// --
982
983#[cfg(test)]
984mod tests {
985    extern crate test_case;
986    use super::*;
987    use test_case::test_case;
988
989    // --
990
991    #[test_case("abc_def" => "AbcDef".to_string(); "basic")]
992    #[test_case("abc_def_" => "AbcDef".to_string(); "suffix")]
993    #[test_case("_abc_def"=> "AbcDef".to_string(); "prefix")]
994    #[test_case("abc__def"=> "AbcDef".to_string(); "consecutive")]
995    #[test_case("aBc_dEf"=> "AbcDef".to_string(); "middle")]
996    #[test_case("__abc__def__" => "AbcDef".to_string(); "double middle")]
997    fn test_snake_to_camel(ident_str: &str) -> String {
998        // snake_to_camel(ident_str)
999        snake_to_camel2(ident_str)
1000    }
1001}