model.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. use std::{
  2. collections::{HashMap, HashSet},
  3. hash::Hash,
  4. rc::Rc,
  5. };
  6. use btrun::End;
  7. use proc_macro2::{Ident, Span, TokenStream};
  8. use quote::{format_ident, quote, ToTokens};
  9. use crate::{
  10. case_convert::CaseConvert,
  11. error,
  12. parsing::MessageReplyPart,
  13. parsing::{ActorDef, Dest, GetSpan, Message, Protocol, State, Transition},
  14. };
  15. pub(crate) struct ProtocolModel {
  16. def: Protocol,
  17. msg_lookup: MsgLookup,
  18. actors: HashMap<Rc<Ident>, ActorModel>,
  19. }
  20. impl ProtocolModel {
  21. pub(crate) fn new(def: Protocol) -> syn::Result<Self> {
  22. let actor_lookup = ActorLookup::new(def.actor_defs.iter().map(|x| x.as_ref()));
  23. let msg_lookup = MsgLookup::new(def.transitions.iter().map(|x| x.as_ref()));
  24. let mut actors = HashMap::new();
  25. for actor_def in def.actor_defs.iter() {
  26. let actor_name = &actor_def.actor;
  27. let actor_states = actor_lookup.actor_states(actor_name.as_ref());
  28. let transitions_by_state = actor_states.iter().map(|state_name| {
  29. let transitions = def
  30. .transitions
  31. .iter()
  32. .filter(|transition| {
  33. state_name.as_ref() == transition.in_state.state_trait.as_ref()
  34. })
  35. .cloned();
  36. (state_name.clone(), transitions)
  37. });
  38. let actor = ActorModel::new(actor_def.clone(), &msg_lookup, transitions_by_state)?;
  39. actors.insert(actor_name.clone(), actor);
  40. }
  41. Ok(Self {
  42. def,
  43. msg_lookup,
  44. actors,
  45. })
  46. }
  47. pub(crate) fn def(&self) -> &Protocol {
  48. &self.def
  49. }
  50. pub(crate) fn msg_lookup(&self) -> &MsgLookup {
  51. &self.msg_lookup
  52. }
  53. pub(crate) fn actors_iter(&self) -> impl Iterator<Item = &ActorModel> {
  54. self.actors.values()
  55. }
  56. pub(crate) fn states_iter(&self) -> impl Iterator<Item = &StateModel> {
  57. self.actors_iter().flat_map(|actor| actor.states().values())
  58. }
  59. #[cfg(test)]
  60. pub(crate) fn methods_iter(&self) -> impl Iterator<Item = &MethodModel> {
  61. self.states_iter()
  62. .flat_map(|state| state.methods().values())
  63. }
  64. #[cfg(test)]
  65. pub(crate) fn outputs_iter(&self) -> impl Iterator<Item = &OutputModel> {
  66. self.methods_iter()
  67. .flat_map(|method| method.outputs().iter())
  68. }
  69. }
  70. pub(crate) struct ActorModel {
  71. #[allow(dead_code)]
  72. def: Rc<ActorDef>,
  73. is_client: bool,
  74. states: HashMap<Rc<Ident>, StateModel>,
  75. }
  76. impl ActorModel {
  77. fn new<S, T>(def: Rc<ActorDef>, messages: &MsgLookup, state_iter: S) -> syn::Result<Self>
  78. where
  79. S: IntoIterator<Item = (Rc<Ident>, T)>,
  80. T: IntoIterator<Item = Rc<Transition>>,
  81. {
  82. let transitions: HashMap<_, Vec<_>> = state_iter
  83. .into_iter()
  84. .map(|(name, transitions)| (name, transitions.into_iter().collect()))
  85. .collect();
  86. let is_client = transitions
  87. .values()
  88. .flatten()
  89. .any(|transition| transition.is_client());
  90. let mut states = HashMap::new();
  91. for (name, transitions) in transitions.into_iter() {
  92. let state = StateModel::new(name.clone(), messages, transitions, is_client)?;
  93. if let Some(prev) = states.insert(name, state) {
  94. panic!(
  95. "States are not being grouped by actor correctly. Duplicate state name: '{}'",
  96. prev.name
  97. );
  98. }
  99. }
  100. Ok(Self {
  101. def,
  102. is_client,
  103. states,
  104. })
  105. }
  106. pub(crate) fn is_client(&self) -> bool {
  107. self.is_client
  108. }
  109. pub(crate) fn states(&self) -> &HashMap<Rc<Ident>, StateModel> {
  110. &self.states
  111. }
  112. }
  113. pub(crate) struct StateModel {
  114. name: Rc<Ident>,
  115. methods: HashMap<Rc<Ident>, MethodModel>,
  116. }
  117. impl StateModel {
  118. fn new<T>(
  119. name: Rc<Ident>,
  120. messages: &MsgLookup,
  121. transitions: T,
  122. part_of_client: bool,
  123. ) -> syn::Result<Self>
  124. where
  125. T: IntoIterator<Item = Rc<Transition>>,
  126. {
  127. let mut methods = HashMap::new();
  128. for transition in transitions.into_iter() {
  129. let transition_span = transition.span();
  130. let method = MethodModel::new(transition, messages, part_of_client)?;
  131. if methods.insert(method.name.clone(), method).is_some() {
  132. return Err(syn::Error::new(
  133. transition_span,
  134. error::msgs::DUPLICATE_TRANSITION,
  135. ));
  136. }
  137. }
  138. Ok(Self { name, methods })
  139. }
  140. pub(crate) fn name(&self) -> &Ident {
  141. self.name.as_ref()
  142. }
  143. pub(crate) fn methods(&self) -> &HashMap<Rc<Ident>, MethodModel> {
  144. &self.methods
  145. }
  146. }
  147. impl GetSpan for StateModel {
  148. fn span(&self) -> Span {
  149. self.name.span()
  150. }
  151. }
  152. #[cfg_attr(test, derive(Debug))]
  153. pub(crate) struct MethodModel {
  154. def: Rc<Transition>,
  155. name: Rc<Ident>,
  156. inputs: Vec<InputModel>,
  157. outputs: Vec<OutputModel>,
  158. future: Ident,
  159. }
  160. impl MethodModel {
  161. fn new(def: Rc<Transition>, messages: &MsgLookup, part_of_client: bool) -> syn::Result<Self> {
  162. let name = Rc::new(Self::new_name(def.as_ref())?);
  163. let type_prefix = name.snake_to_pascal();
  164. Ok(Self {
  165. name,
  166. inputs: Self::new_inputs(def.as_ref(), messages, part_of_client),
  167. outputs: Self::new_outputs(def.as_ref(), &type_prefix, messages, part_of_client),
  168. future: format_ident!("{type_prefix}Fut"),
  169. def,
  170. })
  171. }
  172. fn new_name(def: &Transition) -> syn::Result<Ident> {
  173. let name = if let Some(msg) = def.in_msg() {
  174. format_ident!("handle_{}", msg.variant().pascal_to_snake())
  175. } else {
  176. let mut dests = def.out_msgs.as_ref().iter();
  177. let mut msg_names = String::new();
  178. if let Some(dest) = dests.next() {
  179. msg_names.push_str(dest.msg.variant().pascal_to_snake().as_str());
  180. } else {
  181. return Err(syn::Error::new(
  182. def.span(),
  183. error::msgs::NO_MSG_SENT_OR_RECEIVED,
  184. ));
  185. }
  186. for dest in dests {
  187. msg_names.push('_');
  188. msg_names.push_str(dest.msg.variant().pascal_to_snake().as_str());
  189. }
  190. format_ident!("send_{msg_names}")
  191. };
  192. Ok(name)
  193. }
  194. fn new_inputs(def: &Transition, messages: &MsgLookup, part_of_client: bool) -> Vec<InputModel> {
  195. let mut inputs = Vec::new();
  196. if let Some(in_msg) = def.in_msg() {
  197. let msg_info = messages.lookup(in_msg);
  198. inputs.push(InputModel::new(
  199. msg_info.msg_name().clone(),
  200. msg_info.msg_type.clone(),
  201. ))
  202. }
  203. if part_of_client {
  204. for out_msg in def.out_msgs.as_ref().iter() {
  205. let msg_info = messages.lookup(&out_msg.msg);
  206. inputs.push(InputModel::new(
  207. msg_info.msg_name().clone(),
  208. msg_info.msg_type.clone(),
  209. ))
  210. }
  211. }
  212. inputs
  213. }
  214. fn new_outputs(
  215. def: &Transition,
  216. type_prefix: &str,
  217. messages: &MsgLookup,
  218. part_of_client: bool,
  219. ) -> Vec<OutputModel> {
  220. let mut outputs = Vec::new();
  221. for state in def.out_states.as_ref().iter() {
  222. outputs.push(OutputModel::new(
  223. OutputKind::State { def: state.clone() },
  224. type_prefix,
  225. ));
  226. }
  227. for dest in def.out_msgs.as_ref().iter() {
  228. let msg_info = messages.lookup(&dest.msg);
  229. outputs.push(OutputModel::new(
  230. OutputKind::Msg {
  231. def: dest.clone(),
  232. msg_type: msg_info.msg_type.clone(),
  233. is_call: msg_info.is_call(),
  234. part_of_client,
  235. },
  236. type_prefix,
  237. ))
  238. }
  239. outputs
  240. }
  241. pub(crate) fn def(&self) -> &Transition {
  242. self.def.as_ref()
  243. }
  244. pub(crate) fn name(&self) -> &Rc<Ident> {
  245. &self.name
  246. }
  247. pub(crate) fn inputs(&self) -> &Vec<InputModel> {
  248. &self.inputs
  249. }
  250. pub(crate) fn outputs(&self) -> &Vec<OutputModel> {
  251. &self.outputs
  252. }
  253. pub(crate) fn future(&self) -> &Ident {
  254. &self.future
  255. }
  256. }
  257. impl GetSpan for MethodModel {
  258. fn span(&self) -> Span {
  259. self.def.span()
  260. }
  261. }
  262. #[cfg_attr(test, derive(Debug))]
  263. pub(crate) struct InputModel {
  264. name: Ident,
  265. arg_type: Rc<TokenStream>,
  266. }
  267. impl InputModel {
  268. fn new(type_name: Rc<Ident>, arg_type: Rc<TokenStream>) -> Self {
  269. let name = format_ident!("{}_arg", type_name.to_string().pascal_to_snake());
  270. Self { name, arg_type }
  271. }
  272. }
  273. impl ToTokens for InputModel {
  274. fn to_tokens(&self, tokens: &mut TokenStream) {
  275. let name = &self.name;
  276. let arg_type = self.arg_type.as_ref();
  277. tokens.extend(quote! { #name : #arg_type })
  278. }
  279. }
  280. #[cfg_attr(test, derive(Debug))]
  281. pub(crate) struct OutputModel {
  282. type_name: Option<TokenStream>,
  283. decl: Option<TokenStream>,
  284. #[allow(dead_code)]
  285. kind: OutputKind,
  286. }
  287. impl OutputModel {
  288. fn new(kind: OutputKind, type_prefix: &str) -> Self {
  289. let (decl, type_name) = match &kind {
  290. OutputKind::State { def, .. } => {
  291. let state_trait = def.state_trait.as_ref();
  292. if state_trait == End::ident() {
  293. let end_ident = format_ident!("{}", End::ident());
  294. (None, Some(quote! { ::btrun::#end_ident }))
  295. } else {
  296. let type_name = format_ident!("{type_prefix}{}", state_trait);
  297. (
  298. Some(quote! { type #type_name: #state_trait; }),
  299. Some(quote! { Self::#type_name }),
  300. )
  301. }
  302. }
  303. OutputKind::Msg {
  304. msg_type,
  305. part_of_client,
  306. is_call,
  307. ..
  308. } => {
  309. let type_name = if *part_of_client {
  310. if *is_call {
  311. Some(quote! {
  312. <#msg_type as ::btrun::CallMsg>::Reply
  313. })
  314. } else {
  315. None
  316. }
  317. } else {
  318. Some(quote! { #msg_type })
  319. };
  320. (None, type_name)
  321. }
  322. };
  323. Self {
  324. type_name,
  325. decl,
  326. kind,
  327. }
  328. }
  329. pub(crate) fn type_name(&self) -> Option<&TokenStream> {
  330. self.type_name.as_ref()
  331. }
  332. pub(crate) fn decl(&self) -> Option<&TokenStream> {
  333. self.decl.as_ref()
  334. }
  335. }
  336. #[cfg_attr(test, derive(Debug))]
  337. pub(crate) enum OutputKind {
  338. State {
  339. def: Rc<State>,
  340. },
  341. Msg {
  342. #[allow(dead_code)]
  343. def: Rc<Dest>,
  344. msg_type: Rc<TokenStream>,
  345. is_call: bool,
  346. part_of_client: bool,
  347. },
  348. }
  349. pub(crate) struct ActorLookup {
  350. actor_states: HashMap<Rc<Ident>, HashSet<Rc<Ident>>>,
  351. }
  352. impl ActorLookup {
  353. fn new<'a>(actor_defs: impl IntoIterator<Item = &'a ActorDef>) -> Self {
  354. let mut actor_states = HashMap::new();
  355. for actor_def in actor_defs.into_iter() {
  356. let mut states = HashSet::new();
  357. for state in actor_def.states.as_ref().iter() {
  358. states.insert(state.clone());
  359. }
  360. actor_states.insert(actor_def.actor.clone(), states);
  361. }
  362. Self { actor_states }
  363. }
  364. /// Returns the set of states associated with the given actor.
  365. ///
  366. /// This method **panics** if you call it with a non-existent actor name.
  367. pub(crate) fn actor_states(&self, actor_name: &Ident) -> &HashSet<Rc<Ident>> {
  368. self.actor_states.get(actor_name).unwrap_or_else(|| {
  369. panic!("Unknown actor. This indicates there is a bug in the btproto crate.")
  370. })
  371. }
  372. }
  373. pub(crate) struct MsgLookup {
  374. messages: HashMap<Rc<Ident>, MsgInfo>,
  375. }
  376. impl MsgLookup {
  377. fn new<'a>(transitions: impl IntoIterator<Item = &'a Transition>) -> Self {
  378. let mut messages = HashMap::new();
  379. for transition in transitions.into_iter() {
  380. let in_state = &transition.in_state.state_trait;
  381. if let Some(in_msg) = transition.in_msg() {
  382. let msg_name = &in_msg.msg_type;
  383. let msg_info = messages
  384. .entry(msg_name.clone())
  385. .or_insert_with(|| MsgInfo::empty(in_msg.clone()));
  386. msg_info.record_receiver(in_msg, in_state.clone());
  387. }
  388. for dest in transition.out_msgs.as_ref().iter() {
  389. let msg = &dest.msg;
  390. let msg_info = messages
  391. .entry(msg.msg_type.clone())
  392. .or_insert_with(|| MsgInfo::empty(msg.clone()));
  393. msg_info.record_sender(&dest.msg, in_state.clone());
  394. }
  395. }
  396. Self { messages }
  397. }
  398. pub(crate) fn lookup(&self, msg: &Message) -> &MsgInfo {
  399. self.messages
  400. .get(msg.msg_type.as_ref())
  401. // Since a message is either sent or received, and we've added all such messages in
  402. // the new method, this unwrap should not panic.
  403. .unwrap_or_else(|| {
  404. panic!("Failed to find message info. There is a bug in MessageLookup::new.")
  405. })
  406. .info_for(msg)
  407. }
  408. pub(crate) fn msg_iter(&self) -> impl Iterator<Item = &MsgInfo> {
  409. self.messages
  410. .values()
  411. .flat_map(|msg_info| [Some(msg_info), msg_info.reply()])
  412. .flatten()
  413. }
  414. }
  415. impl AsRef<HashMap<Rc<Ident>, MsgInfo>> for MsgLookup {
  416. fn as_ref(&self) -> &HashMap<Rc<Ident>, MsgInfo> {
  417. &self.messages
  418. }
  419. }
  420. #[cfg_attr(test, derive(Debug))]
  421. pub(crate) struct MsgInfo {
  422. def: Rc<Message>,
  423. msg_name: Rc<Ident>,
  424. msg_type: Rc<TokenStream>,
  425. is_reply: bool,
  426. senders: HashSet<Rc<Ident>>,
  427. receivers: HashSet<Rc<Ident>>,
  428. reply: Option<Box<MsgInfo>>,
  429. }
  430. impl MsgInfo {
  431. fn empty(def: Rc<Message>) -> Self {
  432. let msg_name = def.msg_type.as_ref();
  433. Self {
  434. msg_name: def.msg_type.clone(),
  435. msg_type: Rc::new(quote! { #msg_name }),
  436. is_reply: false,
  437. senders: HashSet::new(),
  438. receivers: HashSet::new(),
  439. reply: None,
  440. def,
  441. }
  442. }
  443. fn info_for(&self, msg: &Message) -> &Self {
  444. if msg.is_reply() {
  445. // If this message is a reply, then we should have seen it in MsgLookup::new and
  446. // initialized its reply pointer. So this unwrap shouldn't panic.
  447. self.reply.as_ref().unwrap_or_else(|| {
  448. panic!(
  449. "A reply message was not properly recorded. There is a bug in MessageLookup::new."
  450. )
  451. })
  452. } else {
  453. self
  454. }
  455. }
  456. fn info_for_mut(&mut self, msg: &Rc<Message>) -> &mut Self {
  457. if msg.is_reply() {
  458. self.reply.get_or_insert_with(|| {
  459. let mut reply = MsgInfo::empty(msg.clone());
  460. reply.is_reply = true;
  461. reply.msg_name = Rc::new(format_ident!(
  462. "{}{}",
  463. msg.msg_type.as_ref(),
  464. MessageReplyPart::REPLY_IDENT
  465. ));
  466. let parent = self.msg_name.as_ref();
  467. reply.msg_type = Rc::new(quote! { <#parent as ::btrun::CallMsg>::Reply });
  468. Box::new(reply)
  469. })
  470. } else {
  471. self
  472. }
  473. }
  474. fn record_receiver(&mut self, msg: &Rc<Message>, receiver: Rc<Ident>) {
  475. let target = self.info_for_mut(msg);
  476. target.receivers.insert(receiver);
  477. }
  478. fn record_sender(&mut self, msg: &Rc<Message>, sender: Rc<Ident>) {
  479. let target = self.info_for_mut(msg);
  480. target.senders.insert(sender);
  481. }
  482. pub(crate) fn def(&self) -> &Rc<Message> {
  483. &self.def
  484. }
  485. /// The unique name of this message. If it is a reply, it will end in
  486. /// `MessageReplyPart::REPLY_IDENT`.
  487. pub(crate) fn msg_name(&self) -> &Rc<Ident> {
  488. &self.msg_name
  489. }
  490. /// The type of this message. If this message is not a reply, this is just `msg_name`. If it is
  491. /// a reply, it is `<#msg_name as ::btrun::CallMsg>::Reply`.
  492. pub(crate) fn msg_type(&self) -> &Rc<TokenStream> {
  493. &self.msg_type
  494. }
  495. pub(crate) fn reply(&self) -> Option<&MsgInfo> {
  496. self.reply.as_ref().map(|ptr| ptr.as_ref())
  497. }
  498. pub(crate) fn is_reply(&self) -> bool {
  499. self.is_reply
  500. }
  501. /// Returns true iff this message is a call.
  502. pub(crate) fn is_call(&self) -> bool {
  503. self.reply.is_some()
  504. }
  505. }
  506. impl PartialEq for MsgInfo {
  507. fn eq(&self, other: &Self) -> bool {
  508. self.msg_name.as_ref() == other.msg_name.as_ref()
  509. }
  510. }
  511. impl Eq for MsgInfo {}
  512. impl Hash for MsgInfo {
  513. fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
  514. self.msg_name.hash(state)
  515. }
  516. }
  517. #[cfg(test)]
  518. mod tests {
  519. use crate::{
  520. error::{assert_err, assert_ok},
  521. parsing::{DestinationState, NameDef},
  522. };
  523. use super::*;
  524. #[test]
  525. fn protocol_model_new_minimal_ok() {
  526. let input = Protocol::minimal();
  527. let result = ProtocolModel::new(input);
  528. assert_ok(result);
  529. }
  530. #[test]
  531. fn protocol_model_new_dup_recv_transition_err() {
  532. let input = Protocol::new(
  533. NameDef::new("Undeclared"),
  534. [ActorDef::new("actor", ["Init", "Next"])],
  535. [
  536. Transition::new(
  537. State::new("Init", []),
  538. Some(Message::new("Query", false, [])),
  539. [State::new("Next", [])],
  540. [],
  541. ),
  542. Transition::new(
  543. State::new("Init", []),
  544. Some(Message::new("Query", false, [])),
  545. [State::new("Init", [])],
  546. [],
  547. ),
  548. ],
  549. );
  550. let result = ProtocolModel::new(input);
  551. assert_err(result, error::msgs::DUPLICATE_TRANSITION);
  552. }
  553. #[test]
  554. fn protocol_model_new_dup_send_transition_err() {
  555. let input = Protocol::new(
  556. NameDef::new("Undeclared"),
  557. [
  558. ActorDef::new("server", ["Init", "Next"]),
  559. ActorDef::new("client", ["Client"]),
  560. ],
  561. [
  562. Transition::new(
  563. State::new("Client", []),
  564. None,
  565. [State::new("Client", [])],
  566. [Dest::new(
  567. DestinationState::Individual(State::new("Init", [])),
  568. Message::new("Query", false, []),
  569. )],
  570. ),
  571. Transition::new(
  572. State::new("Client", []),
  573. None,
  574. [State::new("Client", [])],
  575. [Dest::new(
  576. DestinationState::Individual(State::new("Next", [])),
  577. Message::new("Query", false, []),
  578. )],
  579. ),
  580. ],
  581. );
  582. let result = ProtocolModel::new(input);
  583. assert_err(result, error::msgs::DUPLICATE_TRANSITION);
  584. }
  585. #[test]
  586. fn msg_sent_or_received_msg_received_ok() {
  587. let input = Protocol::new(
  588. NameDef::new("Test"),
  589. [ActorDef::new("actor", ["Init"])],
  590. [Transition::new(
  591. State::new("Init", []),
  592. Some(Message::new("Activate", false, [])),
  593. [State::new("End", [])],
  594. [],
  595. )],
  596. );
  597. let result = ProtocolModel::new(input);
  598. assert_ok(result);
  599. }
  600. #[test]
  601. fn msg_sent_or_received_msg_sent_ok() {
  602. let input = Protocol::new(
  603. NameDef::new("Test"),
  604. [ActorDef::new("actor", ["First", "Second"])],
  605. [Transition::new(
  606. State::new("First", []),
  607. None,
  608. [State::new("First", [])],
  609. [Dest::new(
  610. DestinationState::Individual(State::new("Second", [])),
  611. Message::new("Msg", false, []),
  612. )],
  613. )],
  614. );
  615. let result = ProtocolModel::new(input);
  616. assert_ok(result);
  617. }
  618. #[test]
  619. fn msg_sent_or_received_neither_err() {
  620. let input = Protocol::new(
  621. NameDef::new("Test"),
  622. [ActorDef::new("actor", ["First"])],
  623. [Transition::new(
  624. State::new("First", []),
  625. None,
  626. [State::new("First", [])],
  627. [],
  628. )],
  629. );
  630. let result = ProtocolModel::new(input);
  631. assert_err(result, error::msgs::NO_MSG_SENT_OR_RECEIVED);
  632. }
  633. #[test]
  634. fn reply_is_marked_in_output() {
  635. const MSG: &str = "Ping";
  636. let input = Protocol::new(
  637. NameDef::new("ReplyTest"),
  638. [
  639. ActorDef::new("server", ["Listening"]),
  640. ActorDef::new("client", ["Client", "Waiting"]),
  641. ],
  642. [
  643. Transition::new(
  644. State::new("Client", []),
  645. None,
  646. [State::new("Waiting", [])],
  647. [Dest::new(
  648. DestinationState::Service(State::new("Listening", [])),
  649. Message::new(MSG, false, []),
  650. )],
  651. ),
  652. Transition::new(
  653. State::new("Listening", []),
  654. Some(Message::new(MSG, false, [])),
  655. [State::new("Listening", [])],
  656. [Dest::new(
  657. DestinationState::Individual(State::new("Client", [])),
  658. Message::new(MSG, true, []),
  659. )],
  660. ),
  661. Transition::new(
  662. State::new("Waiting", []),
  663. Some(Message::new(MSG, true, [])),
  664. [State::new(End::ident(), [])],
  665. [],
  666. ),
  667. ],
  668. );
  669. let actual = ProtocolModel::new(input).unwrap();
  670. let outputs: Vec<_> = actual
  671. .outputs_iter()
  672. .map(|output| {
  673. if let OutputKind::Msg { is_call, .. } = output.kind {
  674. Some(is_call)
  675. } else {
  676. None
  677. }
  678. })
  679. .filter(|x| x.is_some())
  680. .map(|x| x.unwrap())
  681. .collect();
  682. assert_eq!(2, outputs.len());
  683. assert_eq!(1, outputs.iter().filter(|is_reply| **is_reply).count());
  684. assert_eq!(1, outputs.iter().filter(|is_reply| !*is_reply).count());
  685. }
  686. }