@temporalio/core-bridge 1.15.0 → 1.16.1

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 (209) hide show
  1. package/Cargo.lock +172 -70
  2. package/lib/native.d.ts +1 -1
  3. package/package.json +2 -2
  4. package/releases/aarch64-apple-darwin/index.node +0 -0
  5. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  6. package/releases/x86_64-apple-darwin/index.node +0 -0
  7. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  8. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  9. package/sdk-core/.github/workflows/per-pr.yml +6 -6
  10. package/sdk-core/AGENTS.md +41 -30
  11. package/sdk-core/Cargo.toml +3 -0
  12. package/sdk-core/README.md +15 -9
  13. package/sdk-core/crates/client/Cargo.toml +4 -0
  14. package/sdk-core/crates/client/README.md +139 -0
  15. package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
  16. package/sdk-core/crates/client/src/callback_based.rs +7 -0
  17. package/sdk-core/crates/client/src/errors.rs +294 -0
  18. package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +280 -159
  19. package/sdk-core/crates/client/src/lib.rs +920 -1326
  20. package/sdk-core/crates/client/src/metrics.rs +24 -33
  21. package/sdk-core/crates/client/src/options_structs.rs +457 -0
  22. package/sdk-core/crates/client/src/replaceable.rs +5 -4
  23. package/sdk-core/crates/client/src/request_extensions.rs +8 -9
  24. package/sdk-core/crates/client/src/retry.rs +99 -54
  25. package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +1 -1
  26. package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
  27. package/sdk-core/crates/common/Cargo.toml +61 -2
  28. package/sdk-core/crates/common/build.rs +742 -12
  29. package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
  30. package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
  31. package/sdk-core/crates/common/protos/api_upstream/buf.yaml +0 -3
  32. package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
  33. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +1166 -770
  34. package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +1243 -750
  35. package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +2 -2
  36. package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +4 -3
  37. package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
  38. package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +4 -0
  39. package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +6 -0
  40. package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +16 -1
  41. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +64 -6
  42. package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +88 -33
  43. package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +4 -2
  44. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -0
  45. package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +5 -5
  46. package/sdk-core/crates/common/src/activity_definition.rs +20 -0
  47. package/sdk-core/crates/common/src/data_converters.rs +770 -0
  48. package/sdk-core/crates/common/src/envconfig.rs +5 -0
  49. package/sdk-core/crates/common/src/lib.rs +15 -211
  50. package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
  51. package/sdk-core/crates/common/src/priority.rs +110 -0
  52. package/sdk-core/crates/common/src/protos/canned_histories.rs +3 -0
  53. package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
  54. package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
  55. package/sdk-core/crates/common/src/protos/mod.rs +122 -27
  56. package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
  57. package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
  58. package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +5 -7
  59. package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
  60. package/sdk-core/crates/common/src/telemetry/metrics.rs +268 -223
  61. package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
  62. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
  63. package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
  64. package/sdk-core/crates/common/src/telemetry.rs +264 -4
  65. package/sdk-core/crates/common/src/worker.rs +68 -603
  66. package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
  67. package/sdk-core/crates/macros/Cargo.toml +5 -1
  68. package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
  69. package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
  70. package/sdk-core/crates/macros/src/lib.rs +138 -512
  71. package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
  72. package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
  73. package/sdk-core/crates/sdk/Cargo.toml +19 -6
  74. package/sdk-core/crates/sdk/README.md +415 -0
  75. package/sdk-core/crates/sdk/src/activities.rs +417 -0
  76. package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
  77. package/sdk-core/crates/sdk/src/lib.rs +757 -442
  78. package/sdk-core/crates/sdk/src/workflow_context/options.rs +45 -35
  79. package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
  80. package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
  81. package/sdk-core/crates/sdk/src/workflows.rs +711 -0
  82. package/sdk-core/crates/sdk-core/Cargo.toml +57 -64
  83. package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +41 -35
  84. package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
  85. package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
  86. package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
  87. package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +13 -15
  88. package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
  89. package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
  90. package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
  91. package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +493 -26
  92. package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +4 -8
  93. package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +7 -7
  94. package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
  95. package/sdk-core/crates/sdk-core/src/lib.rs +41 -111
  96. package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
  97. package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +118 -19
  98. package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
  99. package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
  100. package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +179 -196
  101. package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -280
  102. package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +6 -9
  103. package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
  104. package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
  105. package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
  106. package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +9 -5
  107. package/sdk-core/crates/sdk-core/src/worker/client.rs +103 -81
  108. package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +7 -11
  109. package/sdk-core/crates/sdk-core/src/worker/mod.rs +1124 -229
  110. package/sdk-core/crates/sdk-core/src/worker/nexus.rs +145 -23
  111. package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
  112. package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
  113. package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +13 -13
  114. package/sdk-core/crates/sdk-core/src/worker/tuner.rs +28 -8
  115. package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
  116. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
  117. package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +19 -4
  118. package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +14 -18
  119. package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +4 -6
  120. package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
  121. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
  122. package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
  123. package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
  124. package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
  125. package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
  126. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
  127. package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
  128. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
  129. package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
  130. package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
  131. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
  132. package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
  133. package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
  134. package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
  135. package/sdk-core/crates/sdk-core/tests/common/mod.rs +241 -196
  136. package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
  137. package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +3 -5
  138. package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -64
  139. package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +298 -252
  140. package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
  141. package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
  142. package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
  143. package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +16 -12
  144. package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +48 -40
  145. package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +327 -255
  146. package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
  147. package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +147 -126
  148. package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
  149. package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -453
  150. package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
  151. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +360 -231
  152. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +248 -185
  153. package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -43
  154. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
  155. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +428 -315
  156. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -56
  157. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -28
  158. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -243
  159. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
  160. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +101 -42
  161. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -147
  162. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -28
  163. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1036
  164. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -41
  165. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +397 -238
  166. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +414 -189
  167. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
  168. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
  169. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +154 -137
  170. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -105
  171. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -38
  172. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -40
  173. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -54
  174. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +363 -226
  175. package/sdk-core/crates/sdk-core/tests/main.rs +17 -15
  176. package/sdk-core/crates/sdk-core/tests/manual_tests.rs +207 -152
  177. package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +65 -34
  178. package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
  179. package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
  180. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
  181. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
  182. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
  183. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
  184. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
  185. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
  186. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
  187. package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
  188. package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +7 -1
  189. package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +14 -14
  190. package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +83 -74
  191. package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +9 -14
  192. package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +1 -2
  193. package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +13 -13
  194. package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +6 -6
  195. package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +3 -4
  196. package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +62 -75
  197. package/sdk-core/rustfmt.toml +2 -1
  198. package/src/client.rs +205 -318
  199. package/src/metrics.rs +22 -30
  200. package/src/runtime.rs +4 -5
  201. package/src/worker.rs +16 -19
  202. package/ts/native.ts +1 -1
  203. package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
  204. package/sdk-core/crates/common/src/errors.rs +0 -85
  205. package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
  206. package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
  207. package/sdk-core/crates/sdk/src/app_data.rs +0 -37
  208. package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
  209. package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
@@ -0,0 +1,60 @@
1
+ use crate::data_converters::{TemporalDeserializable, TemporalSerializable};
2
+
3
+ /// Implement on a marker struct to define a workflow.
4
+ ///
5
+ /// Typically, you will want to use the `#[workflow]` and `#[workflow_methods]` macros to define
6
+ /// workflows. However, this trait may be implemented manually if desired.
7
+ pub trait WorkflowDefinition {
8
+ /// Type of the input argument to the workflow
9
+ type Input: TemporalDeserializable + TemporalSerializable + 'static;
10
+ /// Type of the output of the workflow
11
+ type Output: TemporalDeserializable + TemporalSerializable + 'static;
12
+ /// The workflow type name
13
+ fn name(&self) -> &str;
14
+ }
15
+
16
+ /// Implement on a marker struct to define a query.
17
+ ///
18
+ /// Typically, you will want to use the `#[query]` attribute inside a `#[workflow_methods]` macro
19
+ /// to define updates. However, this trait may be implemented manually if desired.
20
+ pub trait QueryDefinition {
21
+ /// The workflow type this query belongs to
22
+ type Workflow: WorkflowDefinition;
23
+ /// Type of the input argument to the query.
24
+ type Input: TemporalDeserializable + TemporalSerializable + 'static;
25
+ /// Type of the output of the query.
26
+ type Output: TemporalDeserializable + TemporalSerializable + 'static;
27
+
28
+ /// The workflow type name.
29
+ fn name(&self) -> &str;
30
+ }
31
+
32
+ /// Implement on a marker struct to define a signal.
33
+ ///
34
+ /// Typically, you will want to use the `#[signal]` attribute inside a `#[workflow_methods]` macro
35
+ /// to define signals. However, this trait may be implemented manually if desired.
36
+ pub trait SignalDefinition {
37
+ /// The workflow type this signal belongs to
38
+ type Workflow: WorkflowDefinition;
39
+ /// Type of the input argument to the signal.
40
+ type Input: TemporalDeserializable + TemporalSerializable + 'static;
41
+
42
+ /// The workflow type name.
43
+ fn name(&self) -> &str;
44
+ }
45
+
46
+ /// Implement on a marker struct to define an update.
47
+ ///
48
+ /// Typically, you will want to use the `#[update]` attribute inside a `#[workflow_methods]` macro
49
+ /// to define updates. However, this trait may be implemented manually if desired.
50
+ pub trait UpdateDefinition {
51
+ /// The workflow type this update belongs to
52
+ type Workflow: WorkflowDefinition;
53
+ /// Type of the input argument to the update.
54
+ type Input: TemporalDeserializable + TemporalSerializable + 'static;
55
+ /// Type of the output of the update.
56
+ type Output: TemporalDeserializable + TemporalSerializable + 'static;
57
+
58
+ /// The workflow type name.
59
+ fn name(&self) -> &str;
60
+ }
@@ -5,6 +5,10 @@ edition = "2024"
5
5
  authors = ["Temporal Technologies Inc. <sdk@temporal.io>"]
6
6
  license-file = { workspace = true }
7
7
  description = "Procmacros used in Temporal Core & Rust SDKs"
8
+ homepage = "https://temporal.io/"
9
+ repository = "https://github.com/temporalio/sdk-core"
10
+ keywords = ["temporal", "workflow", "macros"]
11
+ categories = ["development-tools"]
8
12
 
9
13
  [lib]
10
14
  proc-macro = true
@@ -12,7 +16,7 @@ proc-macro = true
12
16
  [dependencies]
13
17
  derive_more = { workspace = true }
14
18
  proc-macro2 = "1.0"
15
- syn = { version = "2.0", features = ["default", "extra-traits"] }
19
+ syn = { version = "2.0", features = ["default", "extra-traits", "full"] }
16
20
  quote = "1.0"
17
21
 
18
22
  [dev-dependencies]
@@ -0,0 +1,585 @@
1
+ use crate::macro_utils::{
2
+ extract_allow_attrs, generate_marker_struct, method_name_to_pascal_case, type_name_string,
3
+ type_to_snake_case,
4
+ };
5
+ use proc_macro::TokenStream;
6
+ use proc_macro2::TokenStream as TokenStream2;
7
+ use quote::{format_ident, quote, quote_spanned};
8
+ use syn::{
9
+ Attribute, FnArg, ImplItem, ItemImpl, ReturnType, Type, TypePath,
10
+ parse::{Parse, ParseStream},
11
+ spanned::Spanned,
12
+ };
13
+
14
+ pub(crate) struct ActivitiesDefinition {
15
+ impl_block: ItemImpl,
16
+ activities: Vec<ActivityMethod>,
17
+ }
18
+
19
+ #[derive(Default)]
20
+ struct ActivityAttributes {
21
+ name_override: Option<syn::Expr>,
22
+ }
23
+
24
+ struct ActivityMethod {
25
+ method: syn::ImplItemFn,
26
+ attributes: ActivityAttributes,
27
+ is_async: bool,
28
+ is_static: bool,
29
+ input_types: Vec<Type>,
30
+ output_type: Option<Type>,
31
+ }
32
+
33
+ impl Parse for ActivitiesDefinition {
34
+ fn parse(input: ParseStream) -> syn::Result<Self> {
35
+ let impl_block: ItemImpl = input.parse()?;
36
+ let mut activities = Vec::new();
37
+
38
+ // Extract methods marked with #[activity]
39
+ for item in &impl_block.items {
40
+ if let ImplItem::Fn(method) = item {
41
+ let has_activity_attr = method
42
+ .attrs
43
+ .iter()
44
+ .any(|attr| attr.path().is_ident("activity"));
45
+
46
+ if has_activity_attr {
47
+ let activity = parse_activity_method(method)?;
48
+ activities.push(activity);
49
+ }
50
+ }
51
+ }
52
+
53
+ Ok(ActivitiesDefinition {
54
+ impl_block,
55
+ activities,
56
+ })
57
+ }
58
+ }
59
+
60
+ fn parse_activity_method(method: &syn::ImplItemFn) -> syn::Result<ActivityMethod> {
61
+ let attributes = extract_activity_attributes(method.attrs.as_slice())?;
62
+ let is_async = method.sig.asyncness.is_some();
63
+
64
+ // Determine if static (no self receiver) or instance (Arc<Self>)
65
+ let is_static = match method.sig.inputs.first() {
66
+ Some(FnArg::Receiver(receiver)) => {
67
+ if receiver.colon_token.is_some() {
68
+ validate_arc_self_type(&receiver.ty)?;
69
+ false
70
+ } else {
71
+ return Err(syn::Error::new_spanned(
72
+ receiver,
73
+ "Activity methods with instance state must use `self: Arc<Self>` as the \
74
+ receiver, not `self`, `&self`, or `&mut self`",
75
+ ));
76
+ }
77
+ }
78
+ Some(FnArg::Typed(_)) | None => true,
79
+ };
80
+
81
+ let input_types = extract_input_types(&method.sig)?;
82
+ let output_type = extract_output_type(&method.sig);
83
+
84
+ Ok(ActivityMethod {
85
+ method: method.clone(),
86
+ attributes,
87
+ is_async,
88
+ is_static,
89
+ input_types,
90
+ output_type,
91
+ })
92
+ }
93
+
94
+ fn extract_activity_attributes(attrs: &[Attribute]) -> syn::Result<ActivityAttributes> {
95
+ let mut activity_attributes = ActivityAttributes::default();
96
+
97
+ for attr in attrs {
98
+ if attr.path().is_ident("activity") && attr.meta.require_list().is_ok() {
99
+ attr.parse_nested_meta(|meta| {
100
+ if meta.path.is_ident("name") {
101
+ let value = meta.value()?;
102
+ let expr: syn::Expr = value.parse()?;
103
+ activity_attributes.name_override = Some(expr);
104
+ Ok(())
105
+ } else {
106
+ Err(meta.error("unsupported activity attribute"))
107
+ }
108
+ })?;
109
+ }
110
+ }
111
+
112
+ Ok(activity_attributes)
113
+ }
114
+
115
+ fn validate_arc_self_type(ty: &Type) -> syn::Result<()> {
116
+ let expected: Type = syn::parse_quote!(Arc<Self>);
117
+
118
+ if let (Type::Path(actual_path), Type::Path(expected_path)) = (ty, &expected)
119
+ && let (Some(actual_seg), Some(expected_seg)) = (
120
+ actual_path.path.segments.last(),
121
+ expected_path.path.segments.last(),
122
+ )
123
+ && actual_seg == expected_seg
124
+ {
125
+ return Ok(());
126
+ }
127
+
128
+ Err(syn::Error::new_spanned(
129
+ ty,
130
+ "Instance activity methods must use `self: Arc<Self>` as the receiver type",
131
+ ))
132
+ }
133
+
134
+ fn extract_input_types(sig: &syn::Signature) -> syn::Result<Vec<Type>> {
135
+ let mut found_ctx = false;
136
+ let mut types = Vec::new();
137
+ for arg in &sig.inputs {
138
+ if let FnArg::Typed(pat_type) = arg {
139
+ if found_ctx {
140
+ types.push((*pat_type.ty).clone());
141
+ } else if let Type::Path(type_path) = &*pat_type.ty
142
+ && type_path
143
+ .path
144
+ .segments
145
+ .last()
146
+ .map(|s| s.ident == "ActivityContext")
147
+ .unwrap_or(false)
148
+ {
149
+ found_ctx = true;
150
+ }
151
+ }
152
+ }
153
+ if !found_ctx {
154
+ return Err(syn::Error::new(
155
+ sig.inputs.span(),
156
+ "Activity functions must have an ActivityContext parameter as either the first \
157
+ parameter, or the second after `self: Arc<Self>`.",
158
+ ));
159
+ }
160
+ if types.len() > 6 {
161
+ return Err(syn::Error::new(
162
+ sig.inputs.span(),
163
+ "Activity functions support at most 6 input parameters (after ActivityContext).",
164
+ ));
165
+ }
166
+ Ok(types)
167
+ }
168
+
169
+ fn extract_output_type(sig: &syn::Signature) -> Option<Type> {
170
+ match &sig.output {
171
+ ReturnType::Type(_, ty) => {
172
+ // Extract T from Result<T, ActivityError>
173
+ if let Type::Path(TypePath { path, .. }) = &**ty
174
+ && let Some(segment) = path.segments.last()
175
+ && segment.ident == "Result"
176
+ && let syn::PathArguments::AngleBracketed(args) = &segment.arguments
177
+ && let Some(syn::GenericArgument::Type(output_ty)) = args.args.first()
178
+ {
179
+ return Some(output_ty.clone());
180
+ }
181
+ // If it's not a Result type, assume it returns the type directly
182
+ Some((**ty).clone())
183
+ }
184
+ ReturnType::Default => None,
185
+ }
186
+ }
187
+
188
+ /// Returns the token stream for the `Input` associated type given the list of input types.
189
+ fn multi_args_input_type(types: &[Type]) -> TokenStream2 {
190
+ match types.len() {
191
+ 0 => quote! { () },
192
+ 1 => {
193
+ let t = &types[0];
194
+ quote! { #t }
195
+ }
196
+ n => {
197
+ let multi_args = format_ident!("MultiArgs{}", n);
198
+ let types = types.iter();
199
+ quote! { ::temporalio_common::data_converters::#multi_args<#(#types),*> }
200
+ }
201
+ }
202
+ }
203
+
204
+ /// Returns the destructuring statement for multi-arg input, or nothing for 0/1 args.
205
+ fn multi_args_destructure(types: &[Type]) -> TokenStream2 {
206
+ let n = types.len();
207
+ if n <= 1 {
208
+ return quote! {};
209
+ }
210
+ let multi_args = format_ident!("MultiArgs{}", n);
211
+ let idents = multi_args_idents(n);
212
+ quote! {
213
+ let ::temporalio_common::data_converters::#multi_args(#(#idents),*) = input;
214
+ }
215
+ }
216
+
217
+ /// Returns identifiers `__arg0`, `__arg1`, ... for N arguments.
218
+ /// For single-arg, returns `input` to preserve backward compatibility.
219
+ fn multi_args_idents(n: usize) -> Vec<syn::Ident> {
220
+ if n == 1 {
221
+ vec![format_ident!("input")]
222
+ } else {
223
+ (0..n).map(|i| format_ident!("__arg{}", i)).collect()
224
+ }
225
+ }
226
+
227
+ impl ActivitiesDefinition {
228
+ pub(crate) fn codegen(&self) -> TokenStream {
229
+ let impl_type = &self.impl_block.self_ty;
230
+ let impl_type_name = type_name_string(impl_type);
231
+ let module_name = type_to_snake_case(impl_type);
232
+ let module_ident = format_ident!("{}", module_name);
233
+
234
+ // Generate the original impl block with:
235
+ // - #[activity] attributes stripped
236
+ // - Activity methods renamed with __ prefix
237
+ let mut cleaned_impl = self.impl_block.clone();
238
+ for item in &mut cleaned_impl.items {
239
+ if let ImplItem::Fn(method) = item {
240
+ let is_activity = method
241
+ .attrs
242
+ .iter()
243
+ .any(|attr| attr.path().is_ident("activity"));
244
+
245
+ method
246
+ .attrs
247
+ .retain(|attr| !attr.path().is_ident("activity"));
248
+
249
+ // Rename activity methods with __ prefix
250
+ if is_activity {
251
+ let new_name = format_ident!("__{}", method.sig.ident);
252
+ method.sig.ident = new_name;
253
+ }
254
+ }
255
+ }
256
+
257
+ // Generate marker structs (inside module, no external references)
258
+ let activity_structs: Vec<_> = self
259
+ .activities
260
+ .iter()
261
+ .map(|act| generate_marker_struct(&act.method))
262
+ .collect();
263
+
264
+ // Generate consts in impl block pointing to marker structs
265
+ let activity_consts: Vec<_> = self
266
+ .activities
267
+ .iter()
268
+ .map(|act| {
269
+ let visibility = &act.method.vis;
270
+ let method_ident = &act.method.sig.ident;
271
+ let struct_name = method_name_to_pascal_case(&act.method.sig.ident);
272
+ let struct_ident = format_ident!("{}", struct_name);
273
+ let span = act.method.span();
274
+ let allow_attrs = extract_allow_attrs(&act.method.attrs);
275
+ quote_spanned! { span=>
276
+ #[allow(non_upper_case_globals)]
277
+ #(#allow_attrs)*
278
+ #visibility const #method_ident: #module_ident::#struct_ident = #module_ident::#struct_ident;
279
+ }
280
+ })
281
+ .collect();
282
+
283
+ // Generate run methods on marker structs (outside module to reference impl_type)
284
+ let run_impls: Vec<_> = self
285
+ .activities
286
+ .iter()
287
+ .map(|act| self.generate_run_impl(act, impl_type, &module_ident))
288
+ .collect();
289
+
290
+ // Generate ActivityDefinition and ExecutableActivity impls (outside module)
291
+ let activity_impls: Vec<_> = self
292
+ .activities
293
+ .iter()
294
+ .map(|act| {
295
+ self.generate_activity_definition_impl(
296
+ act,
297
+ impl_type,
298
+ &impl_type_name,
299
+ &module_ident,
300
+ )
301
+ })
302
+ .collect();
303
+
304
+ let implementer_impl = self.generate_activity_implementer_impl(impl_type, &module_ident);
305
+
306
+ let has_only_static = if self.activities.iter().all(|a| a.is_static) {
307
+ quote! {
308
+ impl ::temporalio_sdk::activities::HasOnlyStaticMethods for #impl_type {}
309
+ }
310
+ } else {
311
+ quote! {}
312
+ };
313
+
314
+ // Generate impl block with consts
315
+ let const_impl = quote! {
316
+ impl #impl_type {
317
+ #(#activity_consts)*
318
+ }
319
+ };
320
+
321
+ let output = quote! {
322
+ #cleaned_impl
323
+
324
+ #const_impl
325
+
326
+ // Module contains only the marker structs (no use super::*)
327
+ mod #module_ident {
328
+ #(#activity_structs)*
329
+ }
330
+
331
+ // Run methods, trait impls are outside the module
332
+ #(#run_impls)*
333
+
334
+ #(#activity_impls)*
335
+
336
+ #implementer_impl
337
+
338
+ #has_only_static
339
+ };
340
+
341
+ output.into()
342
+ }
343
+
344
+ fn generate_run_impl(
345
+ &self,
346
+ activity: &ActivityMethod,
347
+ impl_type: &Type,
348
+ module_ident: &syn::Ident,
349
+ ) -> TokenStream2 {
350
+ let struct_name = method_name_to_pascal_case(&activity.method.sig.ident);
351
+ let struct_ident = format_ident!("{}", struct_name);
352
+ let prefixed_method = format_ident!("__{}", activity.method.sig.ident);
353
+
354
+ let input_type = multi_args_input_type(&activity.input_types);
355
+ let output_type = activity
356
+ .output_type
357
+ .as_ref()
358
+ .map(|t| quote! { #t })
359
+ .unwrap_or(quote! { () });
360
+
361
+ let has_input = !activity.input_types.is_empty();
362
+
363
+ // Build the parameters and call based on static vs instance and input
364
+ let (params, method_call) = if activity.is_static {
365
+ let params = if has_input {
366
+ quote! { self, ctx: ::temporalio_sdk::activities::ActivityContext, input: #input_type }
367
+ } else {
368
+ quote! { self, ctx: ::temporalio_sdk::activities::ActivityContext }
369
+ };
370
+ let call = if has_input {
371
+ let destructure = multi_args_destructure(&activity.input_types);
372
+ let arg_idents = multi_args_idents(activity.input_types.len());
373
+ quote! {
374
+ #destructure
375
+ #impl_type::#prefixed_method(ctx, #(#arg_idents),*)
376
+ }
377
+ } else {
378
+ quote! { #impl_type::#prefixed_method(ctx) }
379
+ };
380
+ (params, call)
381
+ } else {
382
+ let params = if has_input {
383
+ quote! { self, instance: ::std::sync::Arc<#impl_type>, ctx: ::temporalio_sdk::activities::ActivityContext, input: #input_type }
384
+ } else {
385
+ quote! { self, instance: ::std::sync::Arc<#impl_type>, ctx: ::temporalio_sdk::activities::ActivityContext }
386
+ };
387
+ let call = if has_input {
388
+ let destructure = multi_args_destructure(&activity.input_types);
389
+ let arg_idents = multi_args_idents(activity.input_types.len());
390
+ quote! {
391
+ #destructure
392
+ #impl_type::#prefixed_method(instance, ctx, #(#arg_idents),*)
393
+ }
394
+ } else {
395
+ quote! { #impl_type::#prefixed_method(instance, ctx) }
396
+ };
397
+ (params, call)
398
+ };
399
+
400
+ let return_type =
401
+ quote! { Result<#output_type, ::temporalio_sdk::activities::ActivityError> };
402
+
403
+ // If the method returns void (no return type), wrap with Ok(())
404
+ let result_wrapper = if activity.output_type.is_none() {
405
+ quote! { ; Ok(()) }
406
+ } else {
407
+ quote! {}
408
+ };
409
+
410
+ // Common methods for all marker structs
411
+ let common_methods = quote! {
412
+ /// Returns the activity name (delegates to ActivityDefinition::name())
413
+ pub fn name(&self) -> &'static str {
414
+ <Self as ::temporalio_common::ActivityDefinition>::name()
415
+ }
416
+ };
417
+
418
+ if activity.is_async {
419
+ quote! {
420
+ impl #module_ident::#struct_ident {
421
+ #common_methods
422
+
423
+ pub async fn run(#params) -> #return_type {
424
+ #method_call.await #result_wrapper
425
+ }
426
+ }
427
+ }
428
+ } else {
429
+ quote! {
430
+ impl #module_ident::#struct_ident {
431
+ #common_methods
432
+
433
+ pub fn run(#params) -> #return_type {
434
+ #method_call #result_wrapper
435
+ }
436
+ }
437
+ }
438
+ }
439
+ }
440
+
441
+ fn generate_activity_definition_impl(
442
+ &self,
443
+ activity: &ActivityMethod,
444
+ impl_type: &Type,
445
+ impl_type_name: &str,
446
+ module_ident: &syn::Ident,
447
+ ) -> TokenStream2 {
448
+ let struct_name = method_name_to_pascal_case(&activity.method.sig.ident);
449
+ let struct_ident = format_ident!("{}", struct_name);
450
+ let prefixed_method = format_ident!("__{}", activity.method.sig.ident);
451
+
452
+ let input_type = multi_args_input_type(&activity.input_types);
453
+ let output_type = &activity
454
+ .output_type
455
+ .as_ref()
456
+ .map(|t| quote! { #t })
457
+ .unwrap_or(quote! { () });
458
+
459
+ let has_input = !activity.input_types.is_empty();
460
+
461
+ let activity_name = if let Some(ref name_expr) = activity.attributes.name_override {
462
+ quote! { #name_expr }
463
+ } else {
464
+ let default_name = format!("{}::{}", impl_type_name, activity.method.sig.ident);
465
+ quote! { #default_name }
466
+ };
467
+
468
+ let receiver_pattern = if activity.is_static {
469
+ quote! { _receiver }
470
+ } else {
471
+ quote! { receiver }
472
+ };
473
+
474
+ let method_call = if has_input {
475
+ let destructure = multi_args_destructure(&activity.input_types);
476
+ let arg_idents = multi_args_idents(activity.input_types.len());
477
+ if activity.is_static {
478
+ quote! {
479
+ #destructure
480
+ #impl_type::#prefixed_method(ctx, #(#arg_idents),*)
481
+ }
482
+ } else {
483
+ quote! {
484
+ #destructure
485
+ #impl_type::#prefixed_method(receiver.unwrap(), ctx, #(#arg_idents),*)
486
+ }
487
+ }
488
+ } else if activity.is_static {
489
+ quote! { #impl_type::#prefixed_method(ctx) }
490
+ } else {
491
+ quote! { #impl_type::#prefixed_method(receiver.unwrap(), ctx) }
492
+ };
493
+
494
+ let input_param = if has_input {
495
+ quote! { input: Self::Input, }
496
+ } else {
497
+ quote! { _input: Self::Input, }
498
+ };
499
+
500
+ let result_returner = if activity.output_type.is_none() {
501
+ quote! {; Ok(()) }
502
+ } else {
503
+ quote! {}
504
+ };
505
+ let execute_body = if activity.is_async {
506
+ quote! {
507
+ async move { #method_call.await #result_returner }.boxed()
508
+ }
509
+ } else {
510
+ quote! {
511
+ tokio::task::spawn_blocking(move || { #method_call #result_returner })
512
+ .map(|jh| match jh {
513
+ Err(err) => Err(::temporalio_sdk::activities::ActivityError::from(err)),
514
+ Ok(v) => v,
515
+ })
516
+ .boxed()
517
+ }
518
+ };
519
+
520
+ quote! {
521
+ impl ::temporalio_common::ActivityDefinition for #module_ident::#struct_ident {
522
+ type Input = #input_type;
523
+ type Output = #output_type;
524
+
525
+ fn name() -> &'static str
526
+ where
527
+ Self: Sized,
528
+ {
529
+ #activity_name
530
+ }
531
+ }
532
+
533
+ impl ::temporalio_sdk::activities::ExecutableActivity for #module_ident::#struct_ident {
534
+ type Implementer = #impl_type;
535
+
536
+ fn execute(
537
+ #receiver_pattern: Option<::std::sync::Arc<Self::Implementer>>,
538
+ ctx: ::temporalio_sdk::activities::ActivityContext,
539
+ #input_param
540
+ ) -> ::futures::future::BoxFuture<'static,
541
+ Result<Self::Output, ::temporalio_sdk::activities::ActivityError>>
542
+ {
543
+ use ::futures::FutureExt;
544
+
545
+ #execute_body
546
+ }
547
+ }
548
+ }
549
+ }
550
+
551
+ fn generate_activity_implementer_impl(
552
+ &self,
553
+ impl_type: &Type,
554
+ module_ident: &syn::Ident,
555
+ ) -> TokenStream2 {
556
+ let instance_activities: Vec<_> = self
557
+ .activities
558
+ .iter()
559
+ .map(|a| {
560
+ let struct_name = method_name_to_pascal_case(&a.method.sig.ident);
561
+ let struct_ident = format_ident!("{}", struct_name);
562
+ quote! {
563
+ defs.register_activity::<#module_ident::#struct_ident>(self.clone());
564
+ }
565
+ })
566
+ .collect();
567
+
568
+ let register_instance_body = if instance_activities.is_empty() {
569
+ quote! {}
570
+ } else {
571
+ quote! { #(#instance_activities)* }
572
+ };
573
+
574
+ quote! {
575
+ impl ::temporalio_sdk::activities::ActivityImplementer for #impl_type {
576
+ fn register_all(
577
+ self: ::std::sync::Arc<Self>,
578
+ defs: &mut ::temporalio_sdk::activities::ActivityDefinitions,
579
+ ) {
580
+ #register_instance_body
581
+ }
582
+ }
583
+ }
584
+ }
585
+ }