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 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 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 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 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}