@temporalio/core-bridge 1.14.2-canary-release-testing.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/Cargo.lock +794 -650
  2. package/bridge-macros/src/derive_tryintojs.rs +40 -0
  3. package/lib/native.d.ts +24 -3
  4. package/package.json +4 -4
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  11. package/sdk-core/AGENTS.md +42 -31
  12. package/sdk-core/Cargo.toml +4 -1
  13. package/sdk-core/README.md +19 -13
  14. package/sdk-core/crates/client/Cargo.toml +4 -0
  15. package/sdk-core/crates/client/README.md +139 -0
  16. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  17. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  18. package/sdk-core/crates/client/src/errors.rs +294 -0
  19. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +370 -159
  20. package/sdk-core/crates/client/src/lib.rs +920 -1326
  21. package/sdk-core/crates/client/src/metrics.rs +24 -33
  22. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  23. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  24. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  25. package/sdk-core/crates/client/src/retry.rs +99 -54
  26. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +104 -29
  27. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  28. package/sdk-core/crates/common/Cargo.toml +62 -3
  29. package/sdk-core/crates/common/build.rs +742 -12
  30. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  31. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/create-release.yml +0 -5
  32. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  33. package/sdk-core/crates/common/protos/api_upstream/README.md +8 -0
  34. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  35. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +3329 -2647
  36. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +2734 -708
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/activity/v1/message.proto +155 -3
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/common/v1/message.proto +8 -1
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +27 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/activity.proto +81 -0
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -0
  43. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +4 -0
  44. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +15 -0
  45. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +63 -15
  46. package/sdk-core/crates/common/protos/api_upstream/temporal/api/errordetails/v1/message.proto +8 -0
  47. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  48. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +111 -17
  49. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +21 -0
  50. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +20 -1
  51. package/sdk-core/crates/common/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +4 -0
  52. package/sdk-core/crates/common/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
  53. package/sdk-core/crates/common/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -0
  54. package/sdk-core/crates/common/protos/api_upstream/temporal/api/worker/v1/message.proto +4 -7
  55. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflow/v1/message.proto +80 -22
  56. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +347 -23
  57. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +242 -43
  58. package/sdk-core/crates/common/protos/local/temporal/sdk/core/core_interface.proto +15 -0
  59. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +9 -2
  60. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +8 -0
  61. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +22 -5
  62. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  63. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  64. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  65. package/sdk-core/crates/common/src/lib.rs +15 -211
  66. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  67. package/sdk-core/crates/common/src/priority.rs +110 -0
  68. package/sdk-core/crates/common/src/protos/canned_histories.rs +19 -0
  69. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  70. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  71. package/sdk-core/crates/common/src/protos/mod.rs +134 -27
  72. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  73. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  74. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +11 -16
  75. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  76. package/sdk-core/crates/common/src/telemetry/metrics.rs +272 -225
  77. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  78. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  79. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  80. package/sdk-core/crates/common/src/telemetry.rs +278 -19
  81. package/sdk-core/crates/common/src/worker.rs +68 -636
  82. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  83. package/sdk-core/crates/macros/Cargo.toml +5 -1
  84. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  85. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  86. package/sdk-core/crates/macros/src/lib.rs +138 -512
  87. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  88. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  89. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  90. package/sdk-core/crates/sdk/README.md +415 -0
  91. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  92. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  93. package/sdk-core/crates/sdk/src/lib.rs +759 -442
  94. package/sdk-core/crates/sdk/src/workflow_context/options.rs +64 -35
  95. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  96. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  97. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  98. package/sdk-core/crates/sdk-core/Cargo.toml +59 -65
  99. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +45 -54
  100. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  101. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  102. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  103. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +22 -21
  104. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  105. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  106. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  107. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +647 -27
  108. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +46 -41
  109. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +13 -16
  110. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  111. package/sdk-core/crates/sdk-core/src/lib.rs +60 -123
  112. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  113. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +411 -32
  114. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  115. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  116. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +183 -198
  117. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -281
  118. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +35 -16
  119. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  120. package/sdk-core/crates/sdk-core/src/worker/activities/activity_heartbeat_manager.rs +1 -0
  121. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  122. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  123. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +11 -5
  124. package/sdk-core/crates/sdk-core/src/worker/client.rs +104 -86
  125. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +10 -14
  126. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1175 -241
  127. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +150 -23
  128. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  129. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  130. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +25 -27
  131. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +64 -44
  132. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  133. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/patch_state_machine.rs +5 -8
  134. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  135. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +28 -4
  136. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +20 -41
  137. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +50 -9
  138. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  139. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  140. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  141. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  142. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  143. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  144. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  145. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  146. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  147. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  148. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  149. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  150. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  151. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  152. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  153. package/sdk-core/crates/sdk-core/tests/common/mod.rs +281 -236
  154. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  155. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +9 -14
  156. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -66
  157. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +306 -268
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +37 -38
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +49 -40
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +447 -300
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +157 -157
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -463
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +389 -265
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +250 -185
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -49
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +437 -327
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -58
  175. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -30
  176. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -251
  177. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  178. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +110 -46
  179. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -149
  180. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -32
  181. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1040
  182. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -43
  183. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +402 -245
  184. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +343 -207
  185. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  186. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  187. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +155 -140
  188. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -113
  189. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -44
  190. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -48
  191. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -56
  192. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +365 -242
  193. package/sdk-core/crates/sdk-core/tests/main.rs +22 -16
  194. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +233 -187
  195. package/sdk-core/crates/sdk-core/tests/runner.rs +4 -6
  196. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +73 -27
  197. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  198. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  199. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  200. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  201. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  202. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  203. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  204. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  205. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  206. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  207. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +8 -1
  208. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +37 -26
  209. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +180 -87
  210. package/sdk-core/crates/sdk-core-c-bridge/src/lib.rs +89 -5
  211. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +10 -16
  212. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +59 -67
  213. package/sdk-core/crates/sdk-core-c-bridge/src/testing.rs +10 -10
  214. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +57 -22
  215. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +108 -12
  216. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +9 -52
  217. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +74 -91
  218. package/sdk-core/rustfmt.toml +2 -1
  219. package/src/client.rs +206 -289
  220. package/src/helpers/try_into_js.rs +88 -2
  221. package/src/metrics.rs +277 -35
  222. package/src/runtime.rs +94 -45
  223. package/src/testing.rs +9 -16
  224. package/src/worker.rs +86 -68
  225. package/ts/native.ts +39 -3
  226. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  227. package/sdk-core/crates/common/src/errors.rs +0 -85
  228. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  229. package/sdk-core/crates/macros/LICENSE.txt +0 -21
  230. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  231. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  232. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  233. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -0,0 +1,507 @@
1
+ use proc_macro::TokenStream;
2
+ use quote::{quote, quote_spanned};
3
+ use std::collections::{HashMap, HashSet, hash_map::Entry};
4
+ use syn::{
5
+ Error, Fields, Ident, Token, Type, Variant, Visibility, parenthesized,
6
+ parse::{Parse, ParseStream, Result},
7
+ spanned::Spanned,
8
+ };
9
+
10
+ mod kw {
11
+ syn::custom_keyword!(name);
12
+ syn::custom_keyword!(command);
13
+ syn::custom_keyword!(error);
14
+ syn::custom_keyword!(shared);
15
+ syn::custom_keyword!(shared_state);
16
+ }
17
+
18
+ pub(crate) struct StateMachineDefinition {
19
+ visibility: Visibility,
20
+ name: Ident,
21
+ shared_state_type: Option<Type>,
22
+ command_type: Ident,
23
+ error_type: Ident,
24
+ transitions: Vec<Transition>,
25
+ }
26
+
27
+ impl StateMachineDefinition {
28
+ fn is_final_state(&self, state: &Ident) -> bool {
29
+ // If no transitions go from this state, it's a final state.
30
+ !self.transitions.iter().any(|t| t.from == *state)
31
+ }
32
+ }
33
+
34
+ impl Parse for StateMachineDefinition {
35
+ fn parse(input: ParseStream) -> Result<Self> {
36
+ // Parse visibility if present
37
+ let visibility = input.parse()?;
38
+ // parse the state machine name, command type, and error type
39
+ let (name, command_type, error_type, shared_state_type) = parse_machine_types(input)
40
+ .map_err(|mut e| {
41
+ e.combine(Error::new(
42
+ e.span(),
43
+ "The fsm definition should begin with `name MachineName; command CommandType; \
44
+ error ErrorType;` optionally followed by `shared_state SharedStateType;`",
45
+ ));
46
+ e
47
+ })?;
48
+ // Then the state machine definition is simply a sequence of transitions separated by
49
+ // semicolons
50
+ let transitions = input.parse_terminated(Transition::parse, Token![;])?;
51
+ let transitions: Vec<_> = transitions.into_iter().collect();
52
+ // Check for and whine about any identical transitions. We do this here because preserving
53
+ // the order transitions were defined in is important, so simply collecting to a set is
54
+ // not ideal.
55
+ let trans_set: HashSet<_> = transitions.iter().collect();
56
+ if trans_set.len() != transitions.len() {
57
+ return Err(Error::new(
58
+ input.span(),
59
+ "Duplicate transitions are not allowed!",
60
+ ));
61
+ }
62
+ Ok(Self {
63
+ visibility,
64
+ name,
65
+ shared_state_type,
66
+ command_type,
67
+ error_type,
68
+ transitions,
69
+ })
70
+ }
71
+ }
72
+
73
+ fn parse_machine_types(input: ParseStream) -> Result<(Ident, Ident, Ident, Option<Type>)> {
74
+ let _: kw::name = input.parse()?;
75
+ let name: Ident = input.parse()?;
76
+ input.parse::<Token![;]>()?;
77
+
78
+ let _: kw::command = input.parse()?;
79
+ let command_type: Ident = input.parse()?;
80
+ input.parse::<Token![;]>()?;
81
+
82
+ let _: kw::error = input.parse()?;
83
+ let error_type: Ident = input.parse()?;
84
+ input.parse::<Token![;]>()?;
85
+
86
+ let shared_state_type: Option<Type> = if input.peek(kw::shared_state) {
87
+ let _: kw::shared_state = input.parse()?;
88
+ let typep = input.parse()?;
89
+ input.parse::<Token![;]>()?;
90
+ Some(typep)
91
+ } else {
92
+ None
93
+ };
94
+ Ok((name, command_type, error_type, shared_state_type))
95
+ }
96
+
97
+ #[derive(Debug, Clone, Eq, PartialEq, Hash)]
98
+ struct Transition {
99
+ from: Ident,
100
+ to: Vec<Ident>,
101
+ event: Variant,
102
+ handler: Option<Ident>,
103
+ mutates_shared: bool,
104
+ }
105
+
106
+ impl Parse for Transition {
107
+ fn parse(input: ParseStream) -> Result<Self> {
108
+ // Parse the initial state name
109
+ let from: Ident = input.parse()?;
110
+ // Parse at least one dash
111
+ input.parse::<Token![-]>()?;
112
+ while input.peek(Token![-]) {
113
+ input.parse::<Token![-]>()?;
114
+ }
115
+ // Parse transition information inside parens
116
+ let transition_info;
117
+ parenthesized!(transition_info in input);
118
+ // Get the event variant definition
119
+ let event: Variant = transition_info.parse()?;
120
+ // Reject non-unit or single-item-tuple variants
121
+ match &event.fields {
122
+ Fields::Named(_) => {
123
+ return Err(Error::new(
124
+ event.span(),
125
+ "Struct variants are not supported for events",
126
+ ));
127
+ }
128
+ Fields::Unnamed(uf) => {
129
+ if uf.unnamed.len() != 1 {
130
+ return Err(Error::new(
131
+ event.span(),
132
+ "Only tuple variants with exactly one item are supported for events",
133
+ ));
134
+ }
135
+ }
136
+ Fields::Unit => {}
137
+ }
138
+ // Check if there is an event handler, and parse it
139
+ let (mutates_shared, handler) = if transition_info.peek(Token![,]) {
140
+ transition_info.parse::<Token![,]>()?;
141
+ // Check for mut keyword signifying handler wants to mutate shared state
142
+ let mutates = if transition_info.peek(kw::shared) {
143
+ transition_info.parse::<kw::shared>()?;
144
+ true
145
+ } else {
146
+ false
147
+ };
148
+ (mutates, Some(transition_info.parse()?))
149
+ } else {
150
+ (false, None)
151
+ };
152
+ // Parse at least one dash followed by the "arrow"
153
+ input.parse::<Token![-]>()?;
154
+ while input.peek(Token![-]) {
155
+ input.parse::<Token![-]>()?;
156
+ }
157
+ input.parse::<Token![>]>()?;
158
+ // Parse the destination state
159
+ let to: Ident = input.parse()?;
160
+
161
+ Ok(Self {
162
+ from,
163
+ event,
164
+ handler,
165
+ to: vec![to],
166
+ mutates_shared,
167
+ })
168
+ }
169
+ }
170
+
171
+ impl StateMachineDefinition {
172
+ pub(crate) fn codegen(&self) -> TokenStream {
173
+ let visibility = self.visibility.clone();
174
+ // First extract all of the states into a set, and build the enum's insides
175
+ let states = self.all_states();
176
+ let state_variants = states.iter().map(|s| {
177
+ let statestr = s.to_string();
178
+ quote! {
179
+ #[display(#statestr)]
180
+ #s(#s)
181
+ }
182
+ });
183
+ let name = &self.name;
184
+ let name_str = &self.name.to_string();
185
+
186
+ let transition_result_name = Ident::new(&format!("{name}Transition"), name.span());
187
+ let transition_type_alias = quote! {
188
+ type #transition_result_name<Ds, Sm = #name> = TransitionResult<Sm, Ds>;
189
+ };
190
+
191
+ let state_enum_name = Ident::new(&format!("{name}State"), name.span());
192
+ // If user has not defined any shared state, use the unit type.
193
+ let shared_state_type = self
194
+ .shared_state_type
195
+ .clone()
196
+ .unwrap_or_else(|| syn::parse_str("()").unwrap());
197
+ let machine_struct = quote! {
198
+ #[derive(Clone)]
199
+ #visibility struct #name {
200
+ state: ::core::option::Option<#state_enum_name>,
201
+ shared_state: #shared_state_type
202
+ }
203
+ };
204
+ let states_enum = quote! {
205
+ #[derive(::derive_more::From, Clone, ::derive_more::Display)]
206
+ #visibility enum #state_enum_name {
207
+ #(#state_variants),*
208
+ }
209
+ };
210
+ let state_is_final_match_arms = states.iter().map(|s| {
211
+ let val = if self.is_final_state(s) {
212
+ quote! { true }
213
+ } else {
214
+ quote! { false }
215
+ };
216
+ quote! { #state_enum_name::#s(_) => #val }
217
+ });
218
+ let states_enum_impl = quote! {
219
+ impl #state_enum_name {
220
+ fn is_final(&self) -> bool {
221
+ match self {
222
+ #(#state_is_final_match_arms),*
223
+ }
224
+ }
225
+ }
226
+ };
227
+
228
+ // Build the events enum
229
+ let events: HashSet<Variant> = self.transitions.iter().map(|t| t.event.clone()).collect();
230
+ let events_enum_name = Ident::new(&format!("{name}Events"), name.span());
231
+ let events: Vec<_> = events
232
+ .into_iter()
233
+ .map(|v| {
234
+ let vname = v.ident.to_string();
235
+ quote! {
236
+ #[display(#vname)]
237
+ #v
238
+ }
239
+ })
240
+ .collect();
241
+ let events_enum = quote! {
242
+ #[derive(::derive_more::Display)]
243
+ #visibility enum #events_enum_name {
244
+ #(#events),*
245
+ }
246
+ };
247
+
248
+ // Construct the trait implementation
249
+ let cmd_type = &self.command_type;
250
+ let err_type = &self.error_type;
251
+ let mut statemap: HashMap<Ident, Vec<Transition>> = HashMap::new();
252
+ for t in &self.transitions {
253
+ statemap
254
+ .entry(t.from.clone())
255
+ .and_modify(|v| v.push(t.clone()))
256
+ .or_insert_with(|| vec![t.clone()]);
257
+ }
258
+ // Add any states without any transitions to the map
259
+ for s in &states {
260
+ if !statemap.contains_key(s) {
261
+ statemap.insert(s.clone(), vec![]);
262
+ }
263
+ }
264
+ let transition_result_transform = quote! {
265
+ match res.into_cmd_result() {
266
+ Ok((cmds, state)) => {
267
+ self.state = Some(state);
268
+ Ok(cmds)
269
+ }
270
+ Err(e) => Err(e)
271
+ }
272
+ };
273
+ let mut multi_dest_enums = vec![];
274
+ let mut multi_dest_enum_names = HashSet::new();
275
+ let state_branches: Vec<_> = statemap.into_iter().map(|(from, transitions)| {
276
+ let occupied_current_state = quote! { Some(#state_enum_name::#from(state_data)) };
277
+ // Merge transition dest states with the same handler
278
+ let transitions = merge_transition_dests(transitions);
279
+ let event_branches = transitions
280
+ .into_iter()
281
+ .map(|ts| {
282
+ let ev_variant = &ts.event.ident;
283
+ if let Some(ts_fn) = ts.handler.clone() {
284
+ let span = ts_fn.span();
285
+ let trans_type = match ts.to.as_slice() {
286
+ [] => unreachable!("There will be at least one dest state in transitions"),
287
+ [one_to] => quote! {
288
+ #transition_result_name<#one_to>
289
+ },
290
+ multi_dests => {
291
+ let string_dests: Vec<_> = multi_dests.iter()
292
+ .map(ToString::to_string).collect();
293
+ let enum_ident = Ident::new(&string_dests.join("Or"),
294
+ multi_dests[0].span());
295
+ let multi_dest_enum = quote! {
296
+ #[derive(::derive_more::From)]
297
+ #visibility enum #enum_ident {
298
+ #(#multi_dests(#multi_dests)),*
299
+ }
300
+ impl ::core::convert::From<#enum_ident> for #state_enum_name {
301
+ fn from(v: #enum_ident) -> Self {
302
+ match v {
303
+ #( #enum_ident::#multi_dests(sv) =>
304
+ Self::#multi_dests(sv) ),*
305
+ }
306
+ }
307
+ }
308
+ };
309
+ // Deduplicate; two different events may each result in a transition
310
+ // set with the same set of dest states
311
+ if multi_dest_enum_names.insert(enum_ident.clone()) {
312
+ multi_dest_enums.push(multi_dest_enum);
313
+ }
314
+ quote! {
315
+ #transition_result_name<#enum_ident>
316
+ }
317
+ }
318
+ };
319
+ match ts.event.fields {
320
+ Fields::Unnamed(_) => {
321
+ let arglist = if ts.mutates_shared {
322
+ quote! {&mut self.shared_state, val}
323
+ } else {
324
+ quote! {val}
325
+ };
326
+ quote_spanned! { span =>
327
+ #events_enum_name::#ev_variant(val) => {
328
+ let res: #trans_type = state_data.#ts_fn(#arglist);
329
+ #transition_result_transform
330
+ }
331
+ }
332
+ }
333
+ Fields::Unit => {
334
+ let arglist = if ts.mutates_shared {
335
+ quote! {&mut self.shared_state}
336
+ } else {
337
+ quote! {}
338
+ };
339
+ quote_spanned! { span =>
340
+ #events_enum_name::#ev_variant => {
341
+ let res: #trans_type = state_data.#ts_fn(#arglist);
342
+ #transition_result_transform
343
+ }
344
+ }
345
+ }
346
+ Fields::Named(_) => unreachable!(),
347
+ }
348
+ } else {
349
+ // If events do not have a handler, attempt to construct the next state
350
+ // using `Default`.
351
+ if let [new_state] = ts.to.as_slice() {
352
+ let span = new_state.span();
353
+ let default_trans = quote_spanned! { span =>
354
+ let res = TransitionResult::<Self, #new_state>::from::<#from>(state_data);
355
+ #transition_result_transform
356
+ };
357
+ let span = ts.event.span();
358
+ match ts.event.fields {
359
+ Fields::Unnamed(_) => quote_spanned! { span =>
360
+ #events_enum_name::#ev_variant(_val) => {
361
+ #default_trans
362
+ }
363
+ },
364
+ Fields::Unit => quote_spanned! { span =>
365
+ #events_enum_name::#ev_variant => {
366
+ #default_trans
367
+ }
368
+ },
369
+ Fields::Named(_) => unreachable!(),
370
+ }
371
+ } else {
372
+ unreachable!("It should be impossible to have more than one dest state \
373
+ in no-handler transitions")
374
+ }
375
+ }
376
+ })
377
+ // Since most states won't handle every possible event, return an error to that
378
+ // effect
379
+ .chain(std::iter::once(
380
+ quote! { _ => {
381
+ // Restore state in event the transition doesn't match
382
+ self.state = #occupied_current_state;
383
+ return Err(::temporalio_common::fsm_trait::MachineError::InvalidTransition)
384
+ } },
385
+ ));
386
+ quote! {
387
+ #occupied_current_state => match event {
388
+ #(#event_branches),*
389
+ }
390
+ }
391
+ }).chain(std::iter::once(
392
+ quote! {
393
+ None => Err(::temporalio_common::fsm_trait::MachineError::InvalidTransition)
394
+ }
395
+ )).collect();
396
+
397
+ let viz_str = self.visualize();
398
+
399
+ let trait_impl = quote! {
400
+ impl ::temporalio_common::fsm_trait::StateMachine for #name {
401
+ type Error = #err_type;
402
+ type State = #state_enum_name;
403
+ type SharedState = #shared_state_type;
404
+ type Event = #events_enum_name;
405
+ type Command = #cmd_type;
406
+
407
+ fn name(&self) -> &str {
408
+ #name_str
409
+ }
410
+
411
+ fn on_event(&mut self, event: #events_enum_name)
412
+ -> ::core::result::Result<::std::vec::Vec<Self::Command>,
413
+ ::temporalio_common::fsm_trait::MachineError<Self::Error>> {
414
+ let taken_state = self.state.take();
415
+ match taken_state {
416
+ #(#state_branches),*
417
+ }
418
+ }
419
+
420
+ fn state(&self) -> &Self::State {
421
+ self.state.as_ref().unwrap()
422
+ }
423
+
424
+ fn shared_state(&self) -> &Self::SharedState{
425
+ &self.shared_state
426
+ }
427
+
428
+ fn has_reached_final_state(&self) -> bool {
429
+ self.state.as_ref().unwrap().is_final()
430
+ }
431
+
432
+ fn from_parts(state: Self::State, shared: Self::SharedState) -> Self {
433
+ Self { shared_state: shared, state: Some(state) }
434
+ }
435
+
436
+ fn visualizer() -> &'static str {
437
+ #viz_str
438
+ }
439
+ }
440
+ };
441
+
442
+ let output = quote! {
443
+ #transition_type_alias
444
+ #machine_struct
445
+ #states_enum
446
+ #(#multi_dest_enums)*
447
+ #states_enum_impl
448
+ #events_enum
449
+ #trait_impl
450
+ };
451
+
452
+ TokenStream::from(output)
453
+ }
454
+
455
+ fn all_states(&self) -> HashSet<Ident> {
456
+ self.transitions
457
+ .iter()
458
+ .flat_map(|t| {
459
+ let mut states = t.to.clone();
460
+ states.push(t.from.clone());
461
+ states
462
+ })
463
+ .collect()
464
+ }
465
+
466
+ fn visualize(&self) -> String {
467
+ let transitions: Vec<String> = self
468
+ .transitions
469
+ .iter()
470
+ .flat_map(|t| {
471
+ t.to.iter()
472
+ .map(move |d| format!("{} --> {}: {}", t.from, d, t.event.ident))
473
+ })
474
+ // Add all final state transitions
475
+ .chain(
476
+ self.all_states()
477
+ .iter()
478
+ .filter(|s| self.is_final_state(s))
479
+ .map(|s| format!("{s} --> [*]")),
480
+ )
481
+ .collect();
482
+ let transitions = transitions.join("\n");
483
+ format!("@startuml\n{transitions}\n@enduml")
484
+ }
485
+ }
486
+
487
+ /// Merge transition's dest state lists for those with the same from state & handler
488
+ fn merge_transition_dests(transitions: Vec<Transition>) -> Vec<Transition> {
489
+ let mut map = HashMap::<_, Transition>::new();
490
+ for t in transitions {
491
+ // We want to use the transition sans-destinations as the key
492
+ let without_dests = {
493
+ let mut wd = t.clone();
494
+ wd.to = vec![];
495
+ wd
496
+ };
497
+ match map.entry(without_dests) {
498
+ Entry::Occupied(mut e) => {
499
+ e.get_mut().to.extend(t.to.into_iter());
500
+ }
501
+ Entry::Vacant(v) => {
502
+ v.insert(t);
503
+ }
504
+ }
505
+ }
506
+ map.into_values().collect()
507
+ }