generation.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. use std::collections::HashMap;
  2. use proc_macro2::{Ident, TokenStream};
  3. use quote::{format_ident, quote, ToTokens};
  4. use crate::{
  5. case_convert::CaseConvert,
  6. model::{MethodModel, ProtocolModel},
  7. };
  8. impl ToTokens for ProtocolModel {
  9. fn to_tokens(&self, tokens: &mut TokenStream) {
  10. tokens.extend(self.generate_message_enum());
  11. tokens.extend(self.generate_state_traits());
  12. }
  13. }
  14. impl ProtocolModel {
  15. fn generate_message_enum(&self) -> TokenStream {
  16. let msg_lookup = self.msg_lookup();
  17. let variants: Vec<_> = msg_lookup.msg_iter().map(|msg| msg.msg_name()).collect();
  18. let variant_names_map: HashMap<&Ident, String> = variants
  19. .iter()
  20. .map(|variant| (variant.as_ref(), variant.to_string()))
  21. .collect();
  22. let msg_types = msg_lookup.msg_iter().map(|msg| msg.msg_type());
  23. let all_replies = msg_lookup.msg_iter().all(|msg| msg.is_reply());
  24. let enum_name = format_ident!("{}Msgs", self.def().name_def.name);
  25. let enum_kinds_name = format_ident!("{}MsgKinds", self.def().name_def.name);
  26. let name_decl_vec: Vec<(Ident, TokenStream)> = variants
  27. .iter()
  28. .map(|variant| {
  29. let variant_str = variant_names_map.get(variant.as_ref()).unwrap();
  30. let name_ident =
  31. format_ident!("{}_NAME", variant_str.pascal_to_snake().to_uppercase());
  32. let decl = quote! {
  33. static #name_ident: Lazy<Arc<String>> = Lazy::new(|| {
  34. Arc::new(#variant_str.into())
  35. });
  36. };
  37. (name_ident, decl)
  38. })
  39. .collect();
  40. let name_decls = name_decl_vec.iter().map(|(_, decl)| decl);
  41. let name_idents = name_decl_vec.iter().map(|(ident, _)| ident);
  42. let send_impl = if all_replies {
  43. quote! {}
  44. } else {
  45. quote! {
  46. impl ::btrun::model::SendMsg for #enum_name {}
  47. }
  48. };
  49. let proto_name = &self.def().name_def.name;
  50. let doc_comment = format!("Message type for the {proto_name} protocol.");
  51. quote! {
  52. #[doc = #doc_comment]
  53. #[derive(::serde::Serialize, ::serde::Deserialize)]
  54. pub enum #enum_name {
  55. #( #variants(#msg_types) ),*
  56. }
  57. #[derive(Clone)]
  58. #[allow(dead_code)]
  59. pub enum #enum_kinds_name {
  60. #( #variants ),*
  61. }
  62. impl ::btrun::model::Named for #enum_kinds_name {
  63. fn name(&self) -> ::std::sync::Arc<String> {
  64. use ::btrun::model::Lazy;
  65. use ::std::sync::Arc;
  66. #( #name_decls )*
  67. match self {
  68. #( Self::#variants => #name_idents.clone() ),*
  69. }
  70. }
  71. }
  72. impl Copy for #enum_kinds_name {}
  73. impl ::btrun::model::Named for #enum_name {
  74. fn name(&self) -> ::std::sync::Arc<String> {
  75. match self {
  76. #( Self::#variants(_) => #enum_kinds_name::#variants.name()),*
  77. }
  78. }
  79. }
  80. impl ::btrun::model::CallMsg for #enum_name {
  81. type Reply = Self;
  82. }
  83. #send_impl
  84. }
  85. }
  86. fn generate_state_traits(&self) -> TokenStream {
  87. let traits = self.states_iter().map(|state| {
  88. (
  89. state.name(),
  90. state.methods().values(),
  91. self.actor_lookup()
  92. .actor_with_init_state(state.name())
  93. .is_some(),
  94. )
  95. });
  96. let mut tokens = TokenStream::new();
  97. for (trait_ident, methods, is_init_state) in traits {
  98. let method_tokens = methods.map(|x| x.generate_tokens());
  99. let actor_impl_method = if is_init_state {
  100. quote! {
  101. #[doc = "The name of the implementation for the actor this state is a part of."]
  102. fn actor_impl() -> ::std::sync::Arc<String>;
  103. }
  104. } else {
  105. quote! {}
  106. };
  107. let trait_str = format!("{trait_ident}");
  108. quote! {
  109. pub trait #trait_ident : Send + Sync + Sized {
  110. #actor_impl_method
  111. #( #method_tokens )*
  112. fn state_name() -> ::std::sync::Arc<String> {
  113. use ::btrun::model::Lazy;
  114. use ::std::sync::Arc;
  115. static STATE_NAME: Lazy<Arc<String>> = Lazy::new(|| {
  116. Arc::new(#trait_str.into())
  117. });
  118. STATE_NAME.clone()
  119. }
  120. }
  121. }
  122. .to_tokens(&mut tokens);
  123. }
  124. tokens
  125. }
  126. }
  127. impl MethodModel {
  128. /// Generates the tokens for the code which implements this transition.
  129. fn generate_tokens(&self) -> TokenStream {
  130. let method_ident = self.name().as_ref();
  131. let msg_args = self.inputs().iter();
  132. let output_decls = self.outputs().iter().flat_map(|output| output.decl());
  133. let output_types = self.outputs().iter().flat_map(|output| output.type_name());
  134. let future_name = self.future();
  135. quote! {
  136. #( #output_decls )*
  137. type #future_name: Send + ::std::future::Future<
  138. Output = ::btrun::model::TransResult<Self, ( #( #output_types ),* )>
  139. >;
  140. fn #method_ident(self #( , #msg_args )*) -> Self::#future_name;
  141. }
  142. }
  143. }