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                #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.value
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 value = func(#(#all_state_names)*);
721                            let event = StateEvent {
722                                state: State {
723                                    value,
724                                    timestamp: chrono::Utc::now(),
725                                },
726                                is_touch: false,
727                                close_handle: None,
728                            };
729                            if tx_c.send(event).is_err() {
730                                break;
731                            }
732                        }
733                        Err(_) => break,
734                    }
735                }
736            }
737        })
738        .collect();
739    quote! {
740        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<K>>
741        where
742            #(#tag_typ_cons)*
743            S: 'static + AsState + Send,
744            F: 'static + Fn(#(#fn_params_typ)*) -> S + Send,
745        {
746            let tags: Vec<K> = vec![#(#vec_tags)*];
747            assert!(
748                tags.iter().duplicates().collect::<Vec<_>>().is_empty(),
749                "Should not use duplicate tags."
750            );
751            #(#decl_vars)*
752            #chan_decl
753            tokio::spawn(async move {
754                tracing::info!("merge_reader_{} | {tags:?} -- start", #n);
755                loop {
756                    tokio::select! {
757                        biased;
758                        #(#sel_tokens)*
759                        #(#sel_recvs)*
760                    }
761                }
762                tracing::info!("merge_reader_{} | {tags:?} -- close", #n);
763            });
764            Ok(Reader::new(capacity, tx))
765        }
766    }.into()
767}
768
769#[proc_macro]
770pub fn merge_reader_decl(input: TokenStream) -> TokenStream {
771    let lit_n = parse_macro_input!(input as LitInt);
772    let n = lit_n
773        .base10_parse::<usize>()
774        .expect("Input can only be a number");
775    assert!(n > 1, "Input number should larger than zero.");
776    let method_name = format_ident!("merge_reader_{n}");
777    let tag_typs: Vec<_> = itertools::intersperse(
778        (0..n).map(|i| {
779            let typ = format_ident!("T{}", i);
780            quote! {#typ}
781        }),
782        quote! {,},
783    )
784    .collect();
785    let tag_params: Vec<_> = itertools::intersperse(
786        (0..n).map(|i| {
787            let name = format_ident!("tag_{}", i);
788            let typ = format_ident!("T{}", i);
789            quote! {
790                #name: #typ
791            }
792        }),
793        quote! {,},
794    )
795    .collect();
796    let tag_typ_cons: Vec<_> = (0..n)
797        .map(|i| {
798            let typ = format_ident!("T{}", i);
799            quote! {
800                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
801                #typ::Value: 'static + AsState + Send + Sync,
802            }
803        })
804        .collect();
805    let fn_params_typ: Vec<_> = (0..n)
806        .map(|i| {
807            let typ = format_ident!("T{}", i);
808            quote! {
809                #typ::Value,
810            }
811        })
812        .collect();
813    quote! {
814        /// Merge multiple state readers into one.
815        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<Self::K>>
816        where
817            #(#tag_typ_cons)*
818            S: 'static + AsState + Send,
819            F: 'static + Fn(#(#fn_params_typ)*) -> S + Send;
820    }.into()
821}
822
823#[proc_macro]
824pub fn merge_reader_impl(input: TokenStream) -> TokenStream {
825    let lit_n = parse_macro_input!(input as LitInt);
826    let n = lit_n
827        .base10_parse::<usize>()
828        .expect("Input can only be a number");
829    assert!(n > 1, "Input number should larger than zero.");
830    let method_name = format_ident!("merge_reader_{n}");
831    let tag_typs: Vec<_> = itertools::intersperse(
832        (0..n).map(|i| {
833            let typ = format_ident!("T{}", i);
834            quote! {#typ}
835        }),
836        quote! {,},
837    )
838    .collect();
839    let tag_params: Vec<_> = itertools::intersperse(
840        (0..n).map(|i| {
841            let name = format_ident!("tag_{}", i);
842            let typ = format_ident!("T{}", i);
843            quote! {
844                #name: #typ
845            }
846        }),
847        quote! {,},
848    )
849    .collect();
850    let tag_typ_cons: Vec<_> = (0..n)
851        .map(|i| {
852            let typ = format_ident!("T{}", i);
853            quote! {
854                #typ: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send + Sync,
855                #typ::Value: 'static + AsState + Send + Sync,
856            }
857        })
858        .collect();
859    let fn_params_typ: Vec<_> = (0..n)
860        .map(|i| {
861            let typ = format_ident!("T{}", i);
862            quote! {
863                #typ::Value,
864            }
865        })
866        .collect();
867    let tag_names: Vec<_> = itertools::intersperse(
868        (0..n).map(|i| {
869            let name = format_ident!("tag_{}", i);
870            quote! {
871                #name
872            }
873        }),
874        quote! {,},
875    )
876    .collect();
877    quote! {
878        async fn #method_name<#(#tag_typs)*, S, F>(&self, #(#tag_params)*, func: F) -> Result<Reader<S>, GetHandleError<Self::K>>
879        where
880            #(#tag_typ_cons)*
881            S: 'static + AsState + Send,
882            F: 'static + Fn(#(#fn_params_typ)*) -> S + Send {
883                self.state_machine().#method_name(#(#tag_names)*, func).await
884            }
885    }.into()
886}
887
888#[proc_macro]
889pub fn sm_split_reader(input: TokenStream) -> TokenStream {
890    let lit_n = parse_macro_input!(input as LitInt);
891    let n = lit_n
892        .base10_parse::<usize>()
893        .expect("Input can only be a number");
894    assert!(n > 1, "Input number should larger than one.");
895    let method_name = format_ident!("split_reader_{n}");
896    let state_typs: Vec<_> = itertools::intersperse(
897        (0..n).map(|i| {
898            let typ = format_ident!("S{}", i);
899            quote! {#typ}
900        }),
901        quote! {,},
902    )
903    .collect();
904    let reader_typs: Vec<_> = itertools::intersperse(
905        (0..n).map(|i| {
906            let typ = format_ident!("S{}", i);
907            quote! {Reader<#typ>}
908        }),
909        quote! {,},
910    )
911    .collect();
912    let state_typ_cons: Vec<_> = (0..n)
913        .map(|i| {
914            let typ = format_ident!("S{}", i);
915            quote! {
916                #typ: 'static + AsState + Send,
917            }
918        })
919        .collect();
920    let decl_vars: Vec<_> = (0..n)
921        .map(|i| {
922            let tx_name = format_ident!("tx_{}", i);
923            let tx_name_c = format_ident!("tx_{}_c", i);
924            quote! {
925                let (#tx_name, _) = tokio::sync::broadcast::channel(capacity);
926                let #tx_name_c = #tx_name.clone();
927            }
928        })
929        .collect();
930    let value_names: Vec<_> = itertools::intersperse(
931        (0..n).map(|i| {
932            let value_name = format_ident!("v_{}", i);
933            quote! { #value_name }
934        }),
935        quote! {,},
936    )
937    .collect();
938    let send_states: Vec<_> = (0..n)
939        .map(|i| {
940            let value_name = format_ident!("v_{}", i);
941            let event_name = format_ident!("e_{}", i);
942            let tx_name_c = format_ident!("tx_{}_c", i);
943            quote! {
944                let #event_name = StateEvent {
945                    state: State {
946                        value: #value_name,
947                        timestamp: s_cur.timestamp.clone(),
948                    },
949                    is_touch: false,
950                    close_handle: None,
951                };
952                if #tx_name_c.send(#event_name).is_err() {
953                    break;
954                }
955            }
956        })
957        .collect();
958    let res_readers: Vec<_> = itertools::intersperse(
959        (0..n).map(|i| {
960            let tx_name = format_ident!("tx_{}", i);
961            quote! {
962                Reader::new(capacity, #tx_name)
963            }
964        }),
965        quote! {,},
966    )
967    .collect();
968    quote!{
969        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<K>>
970        where
971            T: 'static + Clone + Debug + Into<K> + KvAssoc + Send,
972            T::Value: 'static + AsState + Send + Sync,
973            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
974            #(#state_typ_cons)*
975        {
976            let handle = self.get_handle(tag.clone())?;
977            let capacity = handle.capacity();
978            let (mut rx, token) = handle.fanout();
979            #(#decl_vars)*
980            let res_typ_name = std::any::type_name::<(#(#reader_typs)*)>();
981            tokio::spawn(async move {
982                tracing::info!("split_reader_{} | {tag:?} | {res_typ_name} -- start", #n);
983                loop {
984                    tokio::select! {
985                        biased;
986                        _ = token.cancelled() => break,
987                        r = rx.recv() => {
988                            match r {
989                                Ok((s_cur, _)) => {
990                                    let (#(#value_names)*) = func(s_cur.value);
991                                    #(#send_states)*
992                                },
993                                Err(_) => break,
994                            }
995                        }
996                    }
997                }
998                tracing::info!("split_reader_{} | {tag:?} | {res_typ_name} -- start", #n);
999            });
1000            Ok((#(#res_readers)*))
1001        }
1002    }.into()
1003}
1004
1005#[proc_macro]
1006pub fn split_reader_decl(input: TokenStream) -> TokenStream {
1007    let lit_n = parse_macro_input!(input as LitInt);
1008    let n = lit_n
1009        .base10_parse::<usize>()
1010        .expect("Input can only be a number");
1011    assert!(n > 1, "Input number should larger than one.");
1012    let method_name = format_ident!("split_reader_{n}");
1013    let state_typs: Vec<_> = itertools::intersperse(
1014        (0..n).map(|i| {
1015            let typ = format_ident!("S{}", i);
1016            quote! {#typ}
1017        }),
1018        quote! {,},
1019    )
1020    .collect();
1021    let reader_typs: Vec<_> = itertools::intersperse(
1022        (0..n).map(|i| {
1023            let typ = format_ident!("S{}", i);
1024            quote! {Reader<#typ>}
1025        }),
1026        quote! {,},
1027    )
1028    .collect();
1029    let state_typ_cons: Vec<_> = (0..n)
1030        .map(|i| {
1031            let typ = format_ident!("S{}", i);
1032            quote! {
1033                #typ: 'static + AsState + Send,
1034            }
1035        })
1036        .collect();
1037    quote!{
1038        /// Split a state reader into multiple state readers.
1039        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<Self::K>>
1040        where
1041            T: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send,
1042            T::Value: 'static + AsState + Send + Sync,
1043            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
1044            #(#state_typ_cons)*;
1045    }.into()
1046}
1047
1048#[proc_macro]
1049pub fn split_reader_impl(input: TokenStream) -> TokenStream {
1050    let lit_n = parse_macro_input!(input as LitInt);
1051    let n = lit_n
1052        .base10_parse::<usize>()
1053        .expect("Input can only be a number");
1054    assert!(n > 1, "Input number should larger than one.");
1055    let method_name = format_ident!("split_reader_{n}");
1056    let state_typs: Vec<_> = itertools::intersperse(
1057        (0..n).map(|i| {
1058            let typ = format_ident!("S{}", i);
1059            quote! {#typ}
1060        }),
1061        quote! {,},
1062    )
1063    .collect();
1064    let reader_typs: Vec<_> = itertools::intersperse(
1065        (0..n).map(|i| {
1066            let typ = format_ident!("S{}", i);
1067            quote! {Reader<#typ>}
1068        }),
1069        quote! {,},
1070    )
1071    .collect();
1072    let state_typ_cons: Vec<_> = (0..n)
1073        .map(|i| {
1074            let typ = format_ident!("S{}", i);
1075            quote! {
1076                #typ: 'static + AsState + Send,
1077            }
1078        })
1079        .collect();
1080    quote!{
1081        async fn #method_name<T, F, #(#state_typs)*>(&self, tag: T, func: F) -> Result<(#(#reader_typs)*), GetHandleError<Self::K>>
1082        where
1083            T: 'static + Clone + Debug + Into<Self::K> + KvAssoc + Send,
1084            T::Value: 'static + AsState + Send + Sync,
1085            F: 'static + Fn(T::Value) -> (#(#state_typs)*) + Send,
1086            #(#state_typ_cons)* {
1087                self.state_machine().#method_name(tag, func).await
1088            }
1089    }.into()
1090}