Skip to main content

state_m_macro/
lib.rs

1use macro_tools::{
2    Assign, AttributeComponent, AttributePropertyComponent, AttributePropertyOptionalSyn, ct, qt,
3    return_syn_err, syn_err,
4};
5use proc_macro::TokenStream;
6use proc_macro2::TokenStream as TokenStream2;
7use quote::{format_ident, quote};
8use syn::{
9    Attribute, DeriveInput, Expr, Ident, Index, LitInt, Type,
10    parse::{Parse, ParseStream},
11    parse_macro_input,
12};
13
14#[derive(Clone, Debug, Default)]
15struct KvAssocArgs {
16    pub assoc: AttributePropertyAssoc,
17    pub label: AttributePropertyLabel,
18}
19
20impl AttributeComponent for KvAssocArgs {
21    const KEYWORD: &'static str = "kv_assoc";
22
23    fn from_meta(attr: &syn::Attribute) -> syn::Result<Self> {
24        match attr.meta {
25            syn::Meta::Path(ref _path) => Ok(Default::default()),
26            syn::Meta::List(ref meta_list) => syn::parse2::<KvAssocArgs>(meta_list.tokens.clone()),
27            syn::Meta::NameValue(_) => return_syn_err!(
28                attr,
29                "Expects an attribute of format `#[kv_assoc(assoc = AssocType, label = \"AssocLabel\")]`. \nGot: {}",
30                qt! { #attr }
31            ),
32        }
33    }
34}
35
36impl Parse for KvAssocArgs {
37    fn parse(input: ParseStream) -> syn::Result<Self> {
38        let mut result = Self::default();
39        let error = |ident: &syn::Ident| -> syn::Error {
40            let known = ct::str::format!(
41                "Known entries of attribute {} are: {}, {}[optional].",
42                KvAssocArgs::KEYWORD,
43                AttributePropertyAssocMarker::KEYWORD,
44                AttributePropertyLabelMarker::KEYWORD,
45            );
46            syn_err!(
47                ident,
48                r#"Expects an attribute of format '#[kv_assoc(assoc = AssocType, label = \"AssocLabel\")]'
49                {known}
50                But got:
51                '{}'"#,
52                qt! { #ident }
53            )
54        };
55        while !input.is_empty() {
56            let lookahead = input.lookahead1();
57            if lookahead.peek(syn::Ident) {
58                let ident: syn::Ident = input.parse()?;
59                match ident.to_string().as_str() {
60                    AttributePropertyAssoc::KEYWORD => {
61                        result.assign(AttributePropertyAssoc::parse(input)?)
62                    }
63                    AttributePropertyLabel::KEYWORD => {
64                        result.assign(AttributePropertyLabel::parse(input)?)
65                    }
66                    _ => return Err(error(&ident)),
67                }
68            } else {
69                return Err(lookahead.error());
70            }
71            // optional trailing comma
72            if input.peek(syn::Token![,]) {
73                input.parse::<syn::Token![,]>()?;
74            }
75        }
76        Ok(result)
77    }
78}
79
80impl<IntoT> Assign<AttributePropertyAssoc, IntoT> for KvAssocArgs
81where
82    IntoT: Into<AttributePropertyAssoc>,
83{
84    #[inline(always)]
85    fn assign(&mut self, component: IntoT) {
86        self.assoc = component.into()
87    }
88}
89
90impl<IntoT> Assign<AttributePropertyLabel, IntoT> for KvAssocArgs
91where
92    IntoT: Into<AttributePropertyLabel>,
93{
94    #[inline(always)]
95    fn assign(&mut self, component: IntoT) {
96        self.label = component.into()
97    }
98}
99
100type AttributePropertyAssoc = AttributePropertyOptionalSyn<Type, AttributePropertyAssocMarker>;
101
102#[derive(Clone, Copy, Debug, Default)]
103struct AttributePropertyAssocMarker;
104
105impl AttributePropertyComponent for AttributePropertyAssocMarker {
106    const KEYWORD: &'static str = "assoc";
107}
108
109type AttributePropertyLabel = AttributePropertyOptionalSyn<Expr, AttributePropertyLabelMarker>;
110
111#[derive(Clone, Copy, Debug, Default)]
112struct AttributePropertyLabelMarker;
113
114impl AttributePropertyComponent for AttributePropertyLabelMarker {
115    const KEYWORD: &'static str = "label";
116}
117
118fn kv_assoc_args(attrs: &Vec<Attribute>) -> KvAssocArgs {
119    let mut args = KvAssocArgs::default();
120    for attr in attrs {
121        if attr.path().is_ident(KvAssocArgs::KEYWORD) {
122            args = KvAssocArgs::from_meta(attr).unwrap_or_else(|e| {
123                panic!(
124                    "Unable to parse attribute [{}] : {}",
125                    KvAssocArgs::KEYWORD,
126                    e
127                )
128            });
129        }
130    }
131    args
132}
133
134fn attrs_except(attrs: &Vec<Attribute>, except: &str) -> Vec<Attribute> {
135    attrs
136        .iter()
137        .filter(|v| !v.path().is_ident(except))
138        .cloned()
139        .collect()
140}
141
142fn q_attrs_except(attrs: &Vec<Attribute>, except: &str) -> TokenStream2 {
143    let attrs_n: Vec<_> = attrs_except(attrs, except);
144    let mut qs: Vec<_> = Vec::new();
145    for attr in attrs_n {
146        qs.push(quote! { #attr });
147    }
148    quote! {
149        #(#qs)*
150    }
151}
152
153#[proc_macro_attribute]
154pub fn state_tag(_attr: TokenStream, item: TokenStream) -> TokenStream {
155    let input = parse_macro_input!(item as DeriveInput);
156    if !input.generics.params.is_empty() {
157        panic!("Generics not supported.");
158    }
159    let i_attrs = &input.attrs;
160    let i_ident = &input.ident;
161    let i_vis = &input.vis;
162    let impl_display = |ident: &Ident, args: KvAssocArgs, quotes: &mut Vec<TokenStream2>| match args
163        .label
164        .internal()
165    {
166        Some(expr) => {
167            quotes.push(quote! {
168                impl std::fmt::Display for #ident {
169                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170                        write!(f, "{}", #expr)
171                    }
172                }
173            });
174        }
175        None => {
176            quotes.push(quote! {
177                impl std::fmt::Display for #ident {
178                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179                        write!(f, "{:?}", self)
180                    }
181                }
182            });
183        }
184    };
185    let mut quotes: Vec<_> = Vec::new();
186    match input.data {
187        syn::Data::Enum(data_enum) => {
188            for item in &data_enum.variants {
189                let q_attrs = q_attrs_except(&item.attrs, KvAssocArgs::KEYWORD);
190                let v_ident = &item.ident;
191                let v_fields = &item.fields;
192                let t_name = format_ident!("{}{}", i_ident, v_ident);
193                let q = match v_fields {
194                    syn::Fields::Named(fields_named) => quote! {
195                        #[derive(Clone, Debug)]
196                        #q_attrs #i_vis struct #t_name #fields_named
197                    },
198                    syn::Fields::Unnamed(fields_unnamed) => quote! {
199                        #[derive(Clone, Debug)]
200                        #q_attrs #i_vis struct #t_name #fields_unnamed;
201                    },
202                    syn::Fields::Unit => quote! {
203                        #[derive(Clone, Debug)]
204                        #q_attrs #i_vis struct #t_name;
205                    },
206                };
207                quotes.push(q);
208
209                let q_fr = match v_fields {
210                    syn::Fields::Named(fields_named) => {
211                        let q_params: Vec<_> = itertools::intersperse(
212                            fields_named.named.iter().map(|field| {
213                                let ident = match field.ident {
214                                    Some(ref ident) => ident.clone(),
215                                    None => panic!("field should be named"),
216                                };
217                                quote! {#ident: value.#ident}
218                            }),
219                            quote! {,},
220                        )
221                        .collect();
222                        quote! {
223                            #i_ident::#v_ident{#(#q_params)*}
224                        }
225                    }
226                    syn::Fields::Unnamed(fields_unnamed) => {
227                        let len = fields_unnamed.unnamed.len();
228                        let q_params: Vec<_> = itertools::intersperse(
229                            (0..len).map(|i| {
230                                let idx = Index::from(i);
231                                quote! {value.#idx}
232                            }),
233                            quote! {,},
234                        )
235                        .collect();
236                        quote! {
237                            #i_ident::#v_ident(#(#q_params)*)
238                        }
239                    }
240                    syn::Fields::Unit => quote! {
241                        #i_ident::#v_ident
242                    },
243                };
244                let q_f = quote! {
245                    impl From<#t_name> for #i_ident {
246                        fn from(value: #t_name) -> #i_ident {
247                            #q_fr
248                        }
249                    }
250                };
251                quotes.push(q_f);
252
253                let args = kv_assoc_args(&item.attrs);
254                match args.clone().assoc.internal() {
255                    Some(typ) => {
256                        quotes.push(quote! {
257                            impl state_m::KvAssoc for #t_name {
258                                type Value = #typ;
259                            }
260                        });
261                    }
262                    None => {
263                        panic!("Expects an attribute of format `#[kv_assoc(assoc = AssocType)]`.")
264                    }
265                }
266                impl_display(&t_name, args, &mut quotes);
267            }
268            let q_attrs = q_attrs_except(i_attrs, KvAssocArgs::KEYWORD);
269            let mut variants = data_enum.variants.clone();
270            for item in variants.iter_mut() {
271                item.attrs = attrs_except(&item.attrs, KvAssocArgs::KEYWORD);
272            }
273            quotes.push(quote! {
274                #q_attrs #i_vis enum #i_ident {
275                    #variants
276                }
277            });
278        }
279        syn::Data::Struct(data_struct) => {
280            let q_attrs = q_attrs_except(i_attrs, KvAssocArgs::KEYWORD);
281            let fields = data_struct.fields;
282            let semi_colon = match data_struct.semi_token {
283                Some(_) => quote! {;},
284                None => quote! {},
285            };
286            let args = kv_assoc_args(&input.attrs);
287            match args.clone().assoc.internal() {
288                Some(typ) => {
289                    quotes.push(quote! {
290                        #q_attrs #i_vis struct #i_ident #fields #semi_colon
291                        impl state_m::KvAssoc for #i_ident {
292                            type Value = #typ;
293                        }
294                    });
295                }
296                None => {
297                    panic!("Expects an attribute of format `#[kv_assoc(assoc = AssocType)]`.")
298                }
299            }
300            impl_display(i_ident, args, &mut quotes);
301        }
302        _ => panic!("Not supported."),
303    };
304    quote! {
305        #(#quotes)*
306    }
307    .into()
308}
309
310#[proc_macro]
311pub fn sm_watch(input: TokenStream) -> TokenStream {
312    let lit_n = parse_macro_input!(input as LitInt);
313    let n = lit_n
314        .base10_parse::<usize>()
315        .expect("Input can only be a number");
316    assert!(n > 0, "Input number should larger than zero.");
317    let method_name = format_ident!("watch_{n}");
318    let tag_typs: Vec<_> = itertools::intersperse(
319        (0..n).map(|i| {
320            let typ = format_ident!("T{}", i);
321            quote! {#typ}
322        }),
323        quote! {,},
324    )
325    .collect();
326    let tag_params: Vec<_> = itertools::intersperse(
327        (0..n).map(|i| {
328            let name = format_ident!("tag_{}", i);
329            let typ = format_ident!("T{}", i);
330            quote! {
331                #name: #typ
332            }
333        }),
334        quote! {,},
335    )
336    .collect();
337    let tag_typ_cons: Vec<_> = (0..n)
338        .map(|i| {
339            let typ = format_ident!("T{}", i);
340            quote! {
341                #typ: 'static + Clone + Debug + Into<K> + KvAssoc + Send + Sync,
342                #typ::Value: 'static + AsState + Send + Sync,
343            }
344        })
345        .collect();
346    let fn_params_typ: Vec<_> = (0..n)
347        .map(|i| {
348            let typ = format_ident!("T{}", i);
349            quote! {
350                StateChange<#typ>,
351            }
352        })
353        .collect();
354    let vec_tags: Vec<_> = itertools::intersperse(
355        (0..n).map(|i| {
356            let name = format_ident!("tag_{}", i);
357            quote! {
358                #name.clone().into()
359            }
360        }),
361        quote! {,},
362    )
363    .collect();
364    let decl_vars: Vec<_> = (0..n)
365        .map(|i| {
366            let tag_name = format_ident!("tag_{}", i);
367            let handle_name = format_ident!("handle_{}", i);
368            let rx_name = format_ident!("rx_{}", i);
369            let token_name = format_ident!("token_{}", i);
370            quote! {
371                    let #handle_name = self.get_handle(#tag_name.clone())?;
372                    let (mut #rx_name, #token_name) = #handle_name.fanout();
373            }
374        })
375        .collect();
376    let all_state_names: Vec<_> = itertools::intersperse(
377        (0..n).map(|i| {
378            let name = format_ident!("state_{}", i);
379            quote! {
380                #name
381            }
382        }),
383        quote! {,},
384    )
385    .collect();
386    let calc_all_states = |idx: usize| {
387        itertools::intersperse(
388            (0..n).map(|i| {
389                if i != idx {
390                    let handle_name = format_ident!("handle_{}", i);
391                    quote! {
392                        StateChange::UnChange(#handle_name.state())
393                    }
394                } else {
395                    quote! {
396                        StateChange::Change(s_cur, s_old)
397                    }
398                }
399            }),
400            quote! {,},
401        )
402        .collect::<Vec<_>>()
403    };
404    let sel_tokens: Vec<_> = (0..n)
405        .map(|i| {
406            let token_name = format_ident!("token_{}", i);
407            quote! {
408                _ = #token_name.cancelled() => break,
409            }
410        })
411        .collect();
412    let sel_recvs: Vec<_> = (0..n)
413        .map(|i| {
414            let all_states = calc_all_states(i);
415            let tag_name = format_ident!("tag_{}", i);
416            let rx_name = format_ident!("rx_{}", i);
417            quote! {
418                r = #rx_name.recv() => {
419                    match r {
420                        Ok((s_cur, s_old)) => {
421                            let mut states = (#(#all_states)*);
422                            let (#(#all_state_names)*) = states;
423                            if let Err(e) = func(#(#all_state_names)*, #tag_name.clone().into()).await {
424                                tracing::error!("watch error -- {e:?}");
425                            }
426                        }
427                        Err(_) => break,
428                    }
429                }
430            }
431        })
432        .collect();
433    quote! {
434        async fn #method_name<#(#tag_typs)*, F>(&self, #(#tag_params)*, func: F) -> Result<(), GetHandleError<K>>
435        where
436            #(#tag_typ_cons)*
437            F: 'static
438                + Fn(
439                    #(#fn_params_typ)* K
440                ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>>
441                + Send,
442        {
443            let tags: Vec<K> = vec![#(#vec_tags)*];
444            assert!(
445                tags.iter().duplicates().collect::<Vec<_>>().is_empty(),
446                "Should not use duplicate tags."
447            );
448            #(#decl_vars)*
449            tokio::spawn(async move {
450                tracing::info!("watch_{} | {tags:?} -- start", #n);
451                loop {
452                    tokio::select! {
453                        biased;
454                        #(#sel_tokens)*
455                        #(#sel_recvs)*
456                    }
457                }
458                tracing::info!("watch_{} | {tags:?} -- close", #n);
459            });
460            Ok(())
461        }
462    }
463    .into()
464}
465
466#[proc_macro]
467pub fn watch_decl(input: TokenStream) -> TokenStream {
468    let lit_n = parse_macro_input!(input as LitInt);
469    let n = lit_n
470        .base10_parse::<usize>()
471        .expect("Input can only be a number");
472    assert!(n > 0, "Input number should larger than zero.");
473    let method_name = format_ident!("watch_{n}");
474    let tag_typs: Vec<_> = itertools::intersperse(
475        (0..n).map(|i| {
476            let typ = format_ident!("T{}", i);
477            quote! {#typ}
478        }),
479        quote! {,},
480    )
481    .collect();
482    let tag_params: Vec<_> = itertools::intersperse(
483        (0..n).map(|i| {
484            let name = format_ident!("tag_{}", i);
485            let typ = format_ident!("T{}", i);
486            quote! {
487                #name: #typ
488            }
489        }),
490        quote! {,},
491    )
492    .collect();
493    let tag_typ_cons: Vec<_> = (0..n)
494        .map(|i| {
495            let typ = format_ident!("T{}", i);
496            quote! {
497                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
498                #typ::Value: 'static + AsState + Send + Sync,
499            }
500        })
501        .collect();
502    let fn_params_typ: Vec<_> = (0..n)
503        .map(|i| {
504            let typ = format_ident!("T{}", i);
505            quote! {
506                StateChange<#typ>,
507            }
508        })
509        .collect();
510    quote! {
511        /// Watch multiple state readers simultaneously, state events from these readers arrived in queue.
512        async fn #method_name<#(#tag_typs)*, F>(&self, #(#tag_params)*, func: F) -> Result<(), GetHandleError<Self::K>>
513        where
514            #(#tag_typ_cons)*
515            F: 'static
516                + Fn(
517                    #(#fn_params_typ)* Self::K
518                ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>>
519                + Send;
520    }
521    .into()
522}
523
524#[proc_macro]
525pub fn watch_impl(input: TokenStream) -> TokenStream {
526    let lit_n = parse_macro_input!(input as LitInt);
527    let n = lit_n
528        .base10_parse::<usize>()
529        .expect("Input can only be a number");
530    assert!(n > 0, "Input number should larger than zero.");
531    let method_name = format_ident!("watch_{n}");
532    let tag_typs: Vec<_> = itertools::intersperse(
533        (0..n).map(|i| {
534            let typ = format_ident!("T{}", i);
535            quote! {#typ}
536        }),
537        quote! {,},
538    )
539    .collect();
540    let tag_params: Vec<_> = itertools::intersperse(
541        (0..n).map(|i| {
542            let name = format_ident!("tag_{}", i);
543            let typ = format_ident!("T{}", i);
544            quote! {
545                #name: #typ
546            }
547        }),
548        quote! {,},
549    )
550    .collect();
551    let tag_typ_cons: Vec<_> = (0..n)
552        .map(|i| {
553            let typ = format_ident!("T{}", i);
554            quote! {
555                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
556                #typ::Value: 'static + AsState + Send + Sync,
557            }
558        })
559        .collect();
560    let fn_params_typ: Vec<_> = (0..n)
561        .map(|i| {
562            let typ = format_ident!("T{}", i);
563            quote! {
564                StateChange<#typ>,
565            }
566        })
567        .collect();
568    let tag_names: Vec<_> = itertools::intersperse(
569        (0..n).map(|i| {
570            let name = format_ident!("tag_{}", i);
571            quote! {
572                #name
573            }
574        }),
575        quote! {,},
576    )
577    .collect();
578    quote! {
579        async fn #method_name<#(#tag_typs)*, F>(&self, #(#tag_params)*, func: F) -> Result<(), GetHandleError<Self::K>>
580        where
581            #(#tag_typ_cons)*
582            F: 'static
583                + Fn(
584                    #(#fn_params_typ)* Self::K
585                ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>>
586                + Send {
587                    self.state_machine().#method_name(#(#tag_names)*, func).await
588                }
589    }
590    .into()
591}
592
593#[proc_macro]
594pub fn sm_merge_reader(input: TokenStream) -> TokenStream {
595    let lit_n = parse_macro_input!(input as LitInt);
596    let n = lit_n
597        .base10_parse::<usize>()
598        .expect("Input can only be a number");
599    assert!(n > 1, "Input number should larger than one.");
600    let method_name = format_ident!("merge_reader_{n}");
601    let tag_typs: Vec<_> = itertools::intersperse(
602        (0..n).map(|i| {
603            let typ = format_ident!("T{}", i);
604            quote! {#typ}
605        }),
606        quote! {,},
607    )
608    .collect();
609    let tag_params: Vec<_> = itertools::intersperse(
610        (0..n).map(|i| {
611            let name = format_ident!("tag_{}", i);
612            let typ = format_ident!("T{}", i);
613            quote! {
614                #name: #typ
615            }
616        }),
617        quote! {,},
618    )
619    .collect();
620    let tag_typ_cons: Vec<_> = (0..n)
621        .map(|i| {
622            let typ = format_ident!("T{}", i);
623            quote! {
624                #typ: 'static + Clone + Debug + Into<K> + KvAssoc + Send + Sync,
625                #typ::Value: 'static + AsState + Send + Sync,
626            }
627        })
628        .collect();
629    let fn_params_typ: Vec<_> = (0..n)
630        .map(|i| {
631            let typ = format_ident!("T{}", i);
632            quote! {
633                State<#typ::Value>,
634            }
635        })
636        .collect();
637    let vec_tags: Vec<_> = itertools::intersperse(
638        (0..n).map(|i| {
639            let name = format_ident!("tag_{}", i);
640            quote! {
641                #name.clone().into()
642            }
643        }),
644        quote! {,},
645    )
646    .collect();
647    let decl_vars: Vec<_> = (0..n)
648        .map(|i| {
649            let tag_name = format_ident!("tag_{}", i);
650            let handle_name = format_ident!("handle_{}", i);
651            let rx_name = format_ident!("rx_{}", i);
652            let token_name = format_ident!("token_{}", i);
653            quote! {
654                    let #handle_name = self.get_handle(#tag_name.clone())?;
655                    let (mut #rx_name, #token_name) = #handle_name.fanout();
656            }
657        })
658        .collect();
659    let chan_decl = {
660        let all_capacities: Vec<_> = itertools::intersperse(
661            (0..n).map(|i| {
662                let handle_name = format_ident!("handle_{}", i);
663                quote! {
664                    #handle_name.capacity()
665                }
666            }),
667            quote! {,},
668        )
669        .collect();
670        quote! {
671            let capacity = itertools::max(vec![#(#all_capacities)*]).expect("Should not happen.");
672            let (tx, _) = tokio::sync::broadcast::channel(capacity);
673            let tx_c = tx.clone();
674        }
675    };
676    let sel_tokens: Vec<_> = (0..n)
677        .map(|i| {
678            let token_name = format_ident!("token_{}", i);
679            quote! {
680                _ = #token_name.cancelled() => break,
681            }
682        })
683        .collect();
684    let calc_state_decls = |idx| {
685        (0..n)
686            .map(|i| {
687                let handle_name = format_ident!("handle_{}", i);
688                let state_name = format_ident!("state_{}", i);
689                if i != idx {
690                    quote! {
691                        let #state_name = #handle_name.state();
692                    }
693                } else {
694                    quote! {
695                        let #state_name = s_cur;
696                    }
697                }
698            })
699            .collect::<Vec<_>>()
700    };
701    let all_state_names: Vec<_> = itertools::intersperse(
702        (0..n).map(|i| {
703            let state_name = format_ident!("state_{}", i);
704            quote! {
705                #state_name
706            }
707        }),
708        quote! {,},
709    )
710    .collect();
711    let sel_recvs: Vec<_> = (0..n)
712        .map(|i| {
713            let state_decls = calc_state_decls(i);
714            let rx_name = format_ident!("rx_{}", i);
715            quote! {
716                r = #rx_name.recv() => {
717                    match r {
718                        Ok((s_cur, _)) => {
719                            #(#state_decls)*
720                            let state = func(#(#all_state_names)*);
721                            let event = StateEvent {
722                                state,
723                                is_touch: false,
724                                close_handle: None,
725                            };
726                            if tx_c.send(event).is_err() {
727                                break;
728                            }
729                        }
730                        Err(_) => break,
731                    }
732                }
733            }
734        })
735        .collect();
736    quote! {
737        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<K>>
738        where
739            #(#tag_typ_cons)*
740            S: 'static + AsState + Send,
741            F: 'static + Fn(#(#fn_params_typ)*) -> State<S> + Send,
742        {
743            let tags: Vec<K> = vec![#(#vec_tags)*];
744            assert!(
745                tags.iter().duplicates().collect::<Vec<_>>().is_empty(),
746                "Should not use duplicate tags."
747            );
748            #(#decl_vars)*
749            #chan_decl
750            tokio::spawn(async move {
751                tracing::info!("merge_reader_{} | {tags:?} -- start", #n);
752                loop {
753                    tokio::select! {
754                        biased;
755                        #(#sel_tokens)*
756                        #(#sel_recvs)*
757                    }
758                }
759                tracing::info!("merge_reader_{} | {tags:?} -- close", #n);
760            });
761            Ok(Reader::new(capacity, tx))
762        }
763    }.into()
764}
765
766#[proc_macro]
767pub fn merge_reader_decl(input: TokenStream) -> TokenStream {
768    let lit_n = parse_macro_input!(input as LitInt);
769    let n = lit_n
770        .base10_parse::<usize>()
771        .expect("Input can only be a number");
772    assert!(n > 1, "Input number should larger than zero.");
773    let method_name = format_ident!("merge_reader_{n}");
774    let tag_typs: Vec<_> = itertools::intersperse(
775        (0..n).map(|i| {
776            let typ = format_ident!("T{}", i);
777            quote! {#typ}
778        }),
779        quote! {,},
780    )
781    .collect();
782    let tag_params: Vec<_> = itertools::intersperse(
783        (0..n).map(|i| {
784            let name = format_ident!("tag_{}", i);
785            let typ = format_ident!("T{}", i);
786            quote! {
787                #name: #typ
788            }
789        }),
790        quote! {,},
791    )
792    .collect();
793    let tag_typ_cons: Vec<_> = (0..n)
794        .map(|i| {
795            let typ = format_ident!("T{}", i);
796            quote! {
797                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
798                #typ::Value: 'static + AsState + Send + Sync,
799            }
800        })
801        .collect();
802    let fn_params_typ: Vec<_> = (0..n)
803        .map(|i| {
804            let typ = format_ident!("T{}", i);
805            quote! {
806                State<#typ::Value>,
807            }
808        })
809        .collect();
810    quote! {
811        /// Merge multiple state readers into one.
812        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<Self::K>>
813        where
814            #(#tag_typ_cons)*
815            S: 'static + AsState + Send,
816            F: 'static + Fn(#(#fn_params_typ)*) -> State<S> + Send;
817    }.into()
818}
819
820#[proc_macro]
821pub fn merge_reader_impl(input: TokenStream) -> TokenStream {
822    let lit_n = parse_macro_input!(input as LitInt);
823    let n = lit_n
824        .base10_parse::<usize>()
825        .expect("Input can only be a number");
826    assert!(n > 1, "Input number should larger than zero.");
827    let method_name = format_ident!("merge_reader_{n}");
828    let tag_typs: Vec<_> = itertools::intersperse(
829        (0..n).map(|i| {
830            let typ = format_ident!("T{}", i);
831            quote! {#typ}
832        }),
833        quote! {,},
834    )
835    .collect();
836    let tag_params: Vec<_> = itertools::intersperse(
837        (0..n).map(|i| {
838            let name = format_ident!("tag_{}", i);
839            let typ = format_ident!("T{}", i);
840            quote! {
841                #name: #typ
842            }
843        }),
844        quote! {,},
845    )
846    .collect();
847    let tag_typ_cons: Vec<_> = (0..n)
848        .map(|i| {
849            let typ = format_ident!("T{}", i);
850            quote! {
851                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
852                #typ::Value: 'static + AsState + Send + Sync,
853            }
854        })
855        .collect();
856    let fn_params_typ: Vec<_> = (0..n)
857        .map(|i| {
858            let typ = format_ident!("T{}", i);
859            quote! {
860                State<#typ::Value>,
861            }
862        })
863        .collect();
864    let tag_names: Vec<_> = itertools::intersperse(
865        (0..n).map(|i| {
866            let name = format_ident!("tag_{}", i);
867            quote! {
868                #name
869            }
870        }),
871        quote! {,},
872    )
873    .collect();
874    quote! {
875        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<Self::K>>
876        where
877            #(#tag_typ_cons)*
878            S: 'static + AsState + Send,
879            F: 'static + Fn(#(#fn_params_typ)*) -> State<S> + Send {
880                self.state_machine().#method_name(#(#tag_names)*, func).await
881            }
882    }.into()
883}
884
885#[proc_macro]
886pub fn sm_split_reader(input: TokenStream) -> TokenStream {
887    let lit_n = parse_macro_input!(input as LitInt);
888    let n = lit_n
889        .base10_parse::<usize>()
890        .expect("Input can only be a number");
891    assert!(n > 1, "Input number should larger than one.");
892    let method_name = format_ident!("split_reader_{n}");
893    let state_typs: Vec<_> = itertools::intersperse(
894        (0..n).map(|i| {
895            let typ = format_ident!("S{}", i);
896            quote! {#typ}
897        }),
898        quote! {,},
899    )
900    .collect();
901    let reader_typs: Vec<_> = itertools::intersperse(
902        (0..n).map(|i| {
903            let typ = format_ident!("S{}", i);
904            quote! {Reader<#typ>}
905        }),
906        quote! {,},
907    )
908    .collect();
909    let state_typ_cons: Vec<_> = (0..n)
910        .map(|i| {
911            let typ = format_ident!("S{}", i);
912            quote! {
913                #typ: 'static + AsState + Send,
914            }
915        })
916        .collect();
917    let decl_vars: Vec<_> = (0..n)
918        .map(|i| {
919            let tx_name = format_ident!("tx_{}", i);
920            let tx_name_c = format_ident!("tx_{}_c", i);
921            quote! {
922                let (#tx_name, _) = tokio::sync::broadcast::channel(capacity);
923                let #tx_name_c = #tx_name.clone();
924            }
925        })
926        .collect();
927    let value_names: Vec<_> = itertools::intersperse(
928        (0..n).map(|i| {
929            let value_name = format_ident!("v_{}", i);
930            quote! { #value_name }
931        }),
932        quote! {,},
933    )
934    .collect();
935    let send_states: Vec<_> = (0..n)
936        .map(|i| {
937            let value_name = format_ident!("v_{}", i);
938            let event_name = format_ident!("e_{}", i);
939            let tx_name_c = format_ident!("tx_{}_c", i);
940            quote! {
941                let #event_name = StateEvent {
942                    state: State {
943                        value: #value_name,
944                        timestamp: s_cur.timestamp.clone(),
945                    },
946                    is_touch: false,
947                    close_handle: None,
948                };
949                if #tx_name_c.send(#event_name).is_err() {
950                    break;
951                }
952            }
953        })
954        .collect();
955    let res_readers: Vec<_> = itertools::intersperse(
956        (0..n).map(|i| {
957            let tx_name = format_ident!("tx_{}", i);
958            quote! {
959                Reader::new(capacity, #tx_name)
960            }
961        }),
962        quote! {,},
963    )
964    .collect();
965    quote!{
966        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<K>>
967        where
968            T: 'static + Clone + Debug + Into<K> + KvAssoc + Send,
969            T::Value: 'static + AsState + Send + Sync,
970            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
971            #(#state_typ_cons)*
972        {
973            let handle = self.get_handle(tag.clone())?;
974            let capacity = handle.capacity();
975            let (mut rx, token) = handle.fanout();
976            #(#decl_vars)*
977            let res_typ_name = std::any::type_name::<(#(#reader_typs)*)>();
978            tokio::spawn(async move {
979                tracing::info!("split_reader_{} | {tag:?} | {res_typ_name} -- start", #n);
980                loop {
981                    tokio::select! {
982                        biased;
983                        _ = token.cancelled() => break,
984                        r = rx.recv() => {
985                            match r {
986                                Ok((s_cur, _)) => {
987                                    let (#(#value_names)*) = func(s_cur.value);
988                                    #(#send_states)*
989                                },
990                                Err(_) => break,
991                            }
992                        }
993                    }
994                }
995                tracing::info!("split_reader_{} | {tag:?} | {res_typ_name} -- start", #n);
996            });
997            Ok((#(#res_readers)*))
998        }
999    }.into()
1000}
1001
1002#[proc_macro]
1003pub fn split_reader_decl(input: TokenStream) -> TokenStream {
1004    let lit_n = parse_macro_input!(input as LitInt);
1005    let n = lit_n
1006        .base10_parse::<usize>()
1007        .expect("Input can only be a number");
1008    assert!(n > 1, "Input number should larger than one.");
1009    let method_name = format_ident!("split_reader_{n}");
1010    let state_typs: Vec<_> = itertools::intersperse(
1011        (0..n).map(|i| {
1012            let typ = format_ident!("S{}", i);
1013            quote! {#typ}
1014        }),
1015        quote! {,},
1016    )
1017    .collect();
1018    let reader_typs: Vec<_> = itertools::intersperse(
1019        (0..n).map(|i| {
1020            let typ = format_ident!("S{}", i);
1021            quote! {Reader<#typ>}
1022        }),
1023        quote! {,},
1024    )
1025    .collect();
1026    let state_typ_cons: Vec<_> = (0..n)
1027        .map(|i| {
1028            let typ = format_ident!("S{}", i);
1029            quote! {
1030                #typ: 'static + AsState + Send,
1031            }
1032        })
1033        .collect();
1034    quote!{
1035        /// Split a state reader into multiple state readers.
1036        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<Self::K>>
1037        where
1038            T: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send,
1039            T::Value: 'static + AsState + Send + Sync,
1040            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
1041            #(#state_typ_cons)*;
1042    }.into()
1043}
1044
1045#[proc_macro]
1046pub fn split_reader_impl(input: TokenStream) -> TokenStream {
1047    let lit_n = parse_macro_input!(input as LitInt);
1048    let n = lit_n
1049        .base10_parse::<usize>()
1050        .expect("Input can only be a number");
1051    assert!(n > 1, "Input number should larger than one.");
1052    let method_name = format_ident!("split_reader_{n}");
1053    let state_typs: Vec<_> = itertools::intersperse(
1054        (0..n).map(|i| {
1055            let typ = format_ident!("S{}", i);
1056            quote! {#typ}
1057        }),
1058        quote! {,},
1059    )
1060    .collect();
1061    let reader_typs: Vec<_> = itertools::intersperse(
1062        (0..n).map(|i| {
1063            let typ = format_ident!("S{}", i);
1064            quote! {Reader<#typ>}
1065        }),
1066        quote! {,},
1067    )
1068    .collect();
1069    let state_typ_cons: Vec<_> = (0..n)
1070        .map(|i| {
1071            let typ = format_ident!("S{}", i);
1072            quote! {
1073                #typ: 'static + AsState + Send,
1074            }
1075        })
1076        .collect();
1077    quote!{
1078        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<Self::K>>
1079        where
1080            T: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send,
1081            T::Value: 'static + AsState + Send + Sync,
1082            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
1083            #(#state_typ_cons)* {
1084                self.state_machine().#method_name(tag, func).await
1085            }
1086    }.into()
1087}