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 #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 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 + Sync,
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 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 + Sync,
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 + Sync,
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}