@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.
- package/Cargo.lock +794 -650
- package/bridge-macros/src/derive_tryintojs.rs +40 -0
- package/lib/native.d.ts +24 -3
- package/package.json +4 -4
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.github/workflows/per-pr.yml +6 -6
- package/sdk-core/AGENTS.md +42 -31
- package/sdk-core/Cargo.toml +4 -1
- package/sdk-core/README.md +19 -13
- package/sdk-core/crates/client/Cargo.toml +4 -0
- package/sdk-core/crates/client/README.md +139 -0
- package/sdk-core/crates/client/src/async_activity_handle.rs +297 -0
- package/sdk-core/crates/client/src/callback_based.rs +7 -0
- package/sdk-core/crates/client/src/errors.rs +294 -0
- package/sdk-core/crates/client/src/{raw.rs → grpc.rs} +370 -159
- package/sdk-core/crates/client/src/lib.rs +920 -1326
- package/sdk-core/crates/client/src/metrics.rs +24 -33
- package/sdk-core/crates/client/src/options_structs.rs +457 -0
- package/sdk-core/crates/client/src/replaceable.rs +5 -4
- package/sdk-core/crates/client/src/request_extensions.rs +8 -9
- package/sdk-core/crates/client/src/retry.rs +99 -54
- package/sdk-core/crates/client/src/{worker/mod.rs → worker.rs} +104 -29
- package/sdk-core/crates/client/src/workflow_handle.rs +826 -0
- package/sdk-core/crates/common/Cargo.toml +62 -3
- package/sdk-core/crates/common/build.rs +742 -12
- package/sdk-core/crates/common/protos/api_upstream/.github/workflows/ci.yml +2 -0
- package/sdk-core/crates/common/protos/api_upstream/.github/workflows/create-release.yml +0 -5
- package/sdk-core/crates/common/protos/api_upstream/Makefile +2 -1
- package/sdk-core/crates/common/protos/api_upstream/README.md +8 -0
- package/sdk-core/crates/common/protos/api_upstream/cmd/check-path-conflicts/main.go +137 -0
- package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv2.json +3329 -2647
- package/sdk-core/crates/common/protos/api_upstream/openapi/openapiv3.yaml +2734 -708
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/activity/v1/message.proto +155 -3
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/common/v1/message.proto +8 -1
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/deployment/v1/message.proto +27 -1
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/activity.proto +81 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/event_type.proto +4 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +4 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +15 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/enums/v1/workflow.proto +63 -15
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/errordetails/v1/message.proto +8 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/failure/v1/message.proto +1 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/history/v1/message.proto +111 -17
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/namespace/v1/message.proto +21 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/nexus/v1/message.proto +20 -1
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +4 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/schedule/v1/message.proto +2 -2
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +2 -0
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/worker/v1/message.proto +4 -7
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflow/v1/message.proto +80 -22
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +347 -23
- package/sdk-core/crates/common/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +242 -43
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/core_interface.proto +15 -0
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/nexus/nexus.proto +9 -2
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +8 -0
- package/sdk-core/crates/common/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +22 -5
- package/sdk-core/crates/common/src/activity_definition.rs +20 -0
- package/sdk-core/crates/common/src/data_converters.rs +770 -0
- package/sdk-core/crates/common/src/envconfig.rs +5 -0
- package/sdk-core/crates/common/src/lib.rs +15 -211
- package/sdk-core/crates/common/src/payload_visitor.rs +648 -0
- package/sdk-core/crates/common/src/priority.rs +110 -0
- package/sdk-core/crates/common/src/protos/canned_histories.rs +19 -0
- package/sdk-core/crates/common/src/protos/history_builder.rs +45 -0
- package/sdk-core/crates/common/src/protos/history_info.rs +2 -0
- package/sdk-core/crates/common/src/protos/mod.rs +134 -27
- package/sdk-core/crates/common/src/protos/task_token.rs +3 -3
- package/sdk-core/crates/common/src/protos/utilities.rs +11 -0
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/log_export.rs +11 -16
- package/sdk-core/crates/common/src/telemetry/metrics/core.rs +125 -0
- package/sdk-core/crates/common/src/telemetry/metrics.rs +272 -225
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/otel.rs +8 -13
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_meter.rs +49 -50
- package/sdk-core/crates/{sdk-core → common}/src/telemetry/prometheus_server.rs +2 -3
- package/sdk-core/crates/common/src/telemetry.rs +278 -19
- package/sdk-core/crates/common/src/worker.rs +68 -636
- package/sdk-core/crates/common/src/workflow_definition.rs +60 -0
- package/sdk-core/crates/macros/Cargo.toml +5 -1
- package/sdk-core/crates/macros/src/activities_definitions.rs +585 -0
- package/sdk-core/crates/macros/src/fsm_impl.rs +507 -0
- package/sdk-core/crates/macros/src/lib.rs +138 -512
- package/sdk-core/crates/macros/src/macro_utils.rs +106 -0
- package/sdk-core/crates/macros/src/workflow_definitions.rs +1224 -0
- package/sdk-core/crates/sdk/Cargo.toml +19 -6
- package/sdk-core/crates/sdk/README.md +415 -0
- package/sdk-core/crates/sdk/src/activities.rs +417 -0
- package/sdk-core/crates/sdk/src/interceptors.rs +1 -1
- package/sdk-core/crates/sdk/src/lib.rs +759 -442
- package/sdk-core/crates/sdk/src/workflow_context/options.rs +64 -35
- package/sdk-core/crates/sdk/src/workflow_context.rs +1033 -289
- package/sdk-core/crates/sdk/src/workflow_future.rs +277 -213
- package/sdk-core/crates/sdk/src/workflows.rs +711 -0
- package/sdk-core/crates/sdk-core/Cargo.toml +59 -65
- package/sdk-core/crates/sdk-core/benches/workflow_replay_bench.rs +45 -54
- package/sdk-core/crates/sdk-core/machine_coverage/ActivityMachine_Coverage.puml +1 -1
- package/sdk-core/crates/sdk-core/src/abstractions.rs +6 -10
- package/sdk-core/crates/sdk-core/src/core_tests/activity_tasks.rs +6 -5
- package/sdk-core/crates/sdk-core/src/core_tests/mod.rs +22 -21
- package/sdk-core/crates/sdk-core/src/core_tests/queries.rs +21 -25
- package/sdk-core/crates/sdk-core/src/core_tests/replay_flag.rs +7 -10
- package/sdk-core/crates/sdk-core/src/core_tests/updates.rs +14 -17
- package/sdk-core/crates/sdk-core/src/core_tests/workers.rs +647 -27
- package/sdk-core/crates/sdk-core/src/core_tests/workflow_tasks.rs +46 -41
- package/sdk-core/crates/sdk-core/src/ephemeral_server/mod.rs +13 -16
- package/sdk-core/crates/sdk-core/src/histfetch.rs +20 -10
- package/sdk-core/crates/sdk-core/src/lib.rs +60 -123
- package/sdk-core/crates/sdk-core/src/pollers/mod.rs +4 -9
- package/sdk-core/crates/sdk-core/src/pollers/poll_buffer.rs +411 -32
- package/sdk-core/crates/sdk-core/src/protosext/mod.rs +2 -2
- package/sdk-core/crates/sdk-core/src/replay/mod.rs +14 -5
- package/sdk-core/crates/sdk-core/src/telemetry/metrics.rs +183 -198
- package/sdk-core/crates/sdk-core/src/telemetry/mod.rs +3 -281
- package/sdk-core/crates/sdk-core/src/test_help/integ_helpers.rs +35 -16
- package/sdk-core/crates/sdk-core/src/test_help/unit_helpers.rs +3 -6
- package/sdk-core/crates/sdk-core/src/worker/activities/activity_heartbeat_manager.rs +1 -0
- package/sdk-core/crates/sdk-core/src/worker/activities/local_activities.rs +11 -14
- package/sdk-core/crates/sdk-core/src/worker/activities.rs +16 -19
- package/sdk-core/crates/sdk-core/src/worker/client/mocks.rs +11 -5
- package/sdk-core/crates/sdk-core/src/worker/client.rs +104 -86
- package/sdk-core/crates/sdk-core/src/worker/heartbeat.rs +10 -14
- package/sdk-core/crates/sdk-core/src/worker/mod.rs +1175 -241
- package/sdk-core/crates/sdk-core/src/worker/nexus.rs +150 -23
- package/sdk-core/crates/sdk-core/src/worker/slot_provider.rs +2 -2
- package/sdk-core/crates/sdk-core/src/worker/tuner/fixed_size.rs +2 -2
- package/sdk-core/crates/sdk-core/src/worker/tuner/resource_based.rs +25 -27
- package/sdk-core/crates/sdk-core/src/worker/tuner.rs +64 -44
- package/sdk-core/crates/sdk-core/src/worker/workflow/driven_workflow.rs +9 -3
- package/sdk-core/crates/sdk-core/src/worker/workflow/machines/patch_state_machine.rs +5 -8
- package/sdk-core/crates/sdk-core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +21 -22
- package/sdk-core/crates/sdk-core/src/worker/workflow/machines/workflow_machines.rs +28 -4
- package/sdk-core/crates/sdk-core/src/worker/workflow/managed_run.rs +20 -41
- package/sdk-core/crates/sdk-core/src/worker/workflow/mod.rs +50 -9
- package/sdk-core/crates/sdk-core/src/worker/workflow/run_cache.rs +4 -7
- package/sdk-core/crates/sdk-core/src/worker/workflow/wft_extraction.rs +2 -4
- package/sdk-core/crates/sdk-core/src/worker/workflow/wft_poller.rs +8 -9
- package/sdk-core/crates/sdk-core/src/worker/workflow/workflow_stream.rs +1 -3
- package/sdk-core/crates/sdk-core/tests/activities_procmacro.rs +6 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/basic_pass.rs +54 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.rs +18 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/invalid_self_type_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.rs +14 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/missing_context_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/multi_arg_pass.rs +48 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_input_pass.rs +14 -0
- package/sdk-core/crates/sdk-core/tests/activities_trybuild/no_return_type_pass.rs +19 -0
- package/sdk-core/crates/sdk-core/tests/cloud_tests.rs +14 -5
- package/sdk-core/crates/sdk-core/tests/common/activity_functions.rs +55 -0
- package/sdk-core/crates/sdk-core/tests/common/mod.rs +281 -236
- package/sdk-core/crates/sdk-core/tests/common/workflows.rs +41 -28
- package/sdk-core/crates/sdk-core/tests/global_metric_tests.rs +9 -14
- package/sdk-core/crates/sdk-core/tests/heavy_tests/fuzzy_workflow.rs +73 -66
- package/sdk-core/crates/sdk-core/tests/heavy_tests.rs +306 -268
- package/sdk-core/crates/sdk-core/tests/integ_tests/async_activity_client_tests.rs +230 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/client_tests.rs +94 -57
- package/sdk-core/crates/sdk-core/tests/integ_tests/data_converter_tests.rs +381 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +37 -38
- package/sdk-core/crates/sdk-core/tests/integ_tests/heartbeat_tests.rs +49 -40
- package/sdk-core/crates/sdk-core/tests/integ_tests/metrics_tests.rs +447 -300
- package/sdk-core/crates/sdk-core/tests/integ_tests/pagination_tests.rs +50 -45
- package/sdk-core/crates/sdk-core/tests/integ_tests/polling_tests.rs +157 -157
- package/sdk-core/crates/sdk-core/tests/integ_tests/queries_tests.rs +103 -89
- package/sdk-core/crates/sdk-core/tests/integ_tests/update_tests.rs +609 -463
- package/sdk-core/crates/sdk-core/tests/integ_tests/visibility_tests.rs +80 -62
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_heartbeat_tests.rs +389 -265
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_tests.rs +250 -185
- package/sdk-core/crates/sdk-core/tests/integ_tests/worker_versioning_tests.rs +52 -49
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_client_tests.rs +180 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/activities.rs +437 -327
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +82 -58
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +56 -30
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +364 -251
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/client_interactions.rs +552 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +110 -46
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +243 -149
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/eager.rs +98 -32
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +1475 -1040
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/modify_wf_properties.rs +73 -43
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +402 -245
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/patches.rs +343 -207
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/queries.rs +415 -0
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/replay.rs +96 -36
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/resets.rs +155 -140
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/signals.rs +183 -113
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +85 -44
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/timers.rs +142 -48
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +73 -56
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests.rs +365 -242
- package/sdk-core/crates/sdk-core/tests/main.rs +22 -16
- package/sdk-core/crates/sdk-core/tests/manual_tests.rs +233 -187
- package/sdk-core/crates/sdk-core/tests/runner.rs +4 -6
- package/sdk-core/crates/sdk-core/tests/shared_tests/mod.rs +73 -27
- package/sdk-core/crates/sdk-core/tests/shared_tests/priority.rs +107 -84
- package/sdk-core/crates/sdk-core/tests/workflows_procmacro.rs +6 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.rs +26 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/async_query_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/basic_pass.rs +49 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/minimal_pass.rs +21 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.rs +26 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/mut_query_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.rs +21 -0
- package/sdk-core/crates/sdk-core/tests/workflows_trybuild/sync_run_fail.stderr +5 -0
- package/sdk-core/crates/sdk-core-c-bridge/Cargo.toml +8 -1
- package/sdk-core/crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h +37 -26
- package/sdk-core/crates/sdk-core-c-bridge/src/client.rs +180 -87
- package/sdk-core/crates/sdk-core-c-bridge/src/lib.rs +89 -5
- package/sdk-core/crates/sdk-core-c-bridge/src/metric.rs +10 -16
- package/sdk-core/crates/sdk-core-c-bridge/src/runtime.rs +59 -67
- package/sdk-core/crates/sdk-core-c-bridge/src/testing.rs +10 -10
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/context.rs +57 -22
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/mod.rs +108 -12
- package/sdk-core/crates/sdk-core-c-bridge/src/tests/utils.rs +9 -52
- package/sdk-core/crates/sdk-core-c-bridge/src/worker.rs +74 -91
- package/sdk-core/rustfmt.toml +2 -1
- package/src/client.rs +206 -289
- package/src/helpers/try_into_js.rs +88 -2
- package/src/metrics.rs +277 -35
- package/src/runtime.rs +94 -45
- package/src/testing.rs +9 -16
- package/src/worker.rs +86 -68
- package/ts/native.ts +39 -3
- package/sdk-core/crates/client/src/workflow_handle/mod.rs +0 -212
- package/sdk-core/crates/common/src/errors.rs +0 -85
- package/sdk-core/crates/common/tests/worker_task_types_test.rs +0 -129
- package/sdk-core/crates/macros/LICENSE.txt +0 -21
- package/sdk-core/crates/sdk/src/activity_context.rs +0 -238
- package/sdk-core/crates/sdk/src/app_data.rs +0 -37
- package/sdk-core/crates/sdk-core/tests/integ_tests/activity_functions.rs +0 -5
- package/sdk-core/crates/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +0 -61
|
@@ -1,21 +1,142 @@
|
|
|
1
1
|
use proc_macro::TokenStream;
|
|
2
|
-
use
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
use syn::parse_macro_input;
|
|
3
|
+
|
|
4
|
+
mod activities_definitions;
|
|
5
|
+
mod fsm_impl;
|
|
6
|
+
mod macro_utils;
|
|
7
|
+
mod workflow_definitions;
|
|
8
|
+
|
|
9
|
+
/// Can be used to define Activities for invocation and execution. Using this macro requires that
|
|
10
|
+
/// you also depend on the `temporalio_sdk` crate.
|
|
11
|
+
///
|
|
12
|
+
/// For a usage example, see that crate's documentation.
|
|
13
|
+
#[proc_macro_attribute]
|
|
14
|
+
pub fn activities(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
15
|
+
let def: activities_definitions::ActivitiesDefinition =
|
|
16
|
+
parse_macro_input!(item as activities_definitions::ActivitiesDefinition);
|
|
17
|
+
def.codegen()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// Marks a method within an `#[activities]` impl block as an activity.
|
|
21
|
+
/// This attribute is processed by the `#[activities]` macro and should not be used standalone.
|
|
22
|
+
#[proc_macro_attribute]
|
|
23
|
+
pub fn activity(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
24
|
+
item
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// Marks a struct as a workflow definition.
|
|
28
|
+
///
|
|
29
|
+
/// This attribute can optionally specify a custom workflow name:
|
|
30
|
+
/// `#[workflow(name = "my-custom-workflow")]`
|
|
31
|
+
///
|
|
32
|
+
/// If no name is specified, the struct name is used as the workflow type name.
|
|
33
|
+
///
|
|
34
|
+
/// This attribute must be used in conjunction with `#[workflow_methods]` on an impl block.
|
|
35
|
+
#[proc_macro_attribute]
|
|
36
|
+
pub fn workflow(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
37
|
+
// Pass through - the struct is not modified, just marked for workflow_methods
|
|
38
|
+
item
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Defines workflow methods for a workflow struct. Using this macro requires that
|
|
42
|
+
/// you also depend on the `temporalio_sdk` crate.
|
|
43
|
+
///
|
|
44
|
+
/// This macro processes an impl block and generates:
|
|
45
|
+
/// - Marker structs for each workflow method
|
|
46
|
+
/// - Trait implementations for workflow definition and execution
|
|
47
|
+
/// - Registration code for workers
|
|
48
|
+
///
|
|
49
|
+
/// ## Macro Attributes
|
|
50
|
+
///
|
|
51
|
+
/// - `factory_only` - When set, the workflow must be registered using
|
|
52
|
+
/// `register_workflow_with_factory` and does not need to implement `Default` or define an `#[init]`
|
|
53
|
+
/// method. Ex: `#[workflow_methods(factory_only)]`
|
|
54
|
+
///
|
|
55
|
+
/// ## Method Attributes
|
|
56
|
+
///
|
|
57
|
+
/// - `#[init]` - Optional initialization method. Signature: `fn new(input: T, ctx: &WorkflowContext) -> Self`
|
|
58
|
+
/// - `#[run]` - Required main workflow function. Signature: `async fn run(&mut self, ctx: &mut WorkflowContext) -> WorkflowResult<T>`
|
|
59
|
+
/// - `#[signal]` - Signal handler. Sync: `fn signal(&mut self, ctx: &mut SyncWorkflowContext, input: T)`. Async: `async fn signal(ctx: &mut WorkflowContext, input: T)`
|
|
60
|
+
/// - `#[query]` - Query handler. Signature: `fn query(&self, ctx: &WorkflowContextView, input: T) -> R` (must NOT be async)
|
|
61
|
+
/// - `#[update]` - Update handler. Sync: `fn update(&mut self, ctx: &mut SyncWorkflowContext, input: T) -> R`. Async: `async fn update(ctx: &mut WorkflowContext, input: T) -> R`
|
|
62
|
+
///
|
|
63
|
+
/// For a usage example, see the `temporalio_sdk` crate's documentation.
|
|
64
|
+
#[proc_macro_attribute]
|
|
65
|
+
pub fn workflow_methods(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
66
|
+
let factory_only = !attr.is_empty() && attr.to_string().contains("factory_only");
|
|
67
|
+
let def: workflow_definitions::WorkflowMethodsDefinition =
|
|
68
|
+
parse_macro_input!(item as workflow_definitions::WorkflowMethodsDefinition);
|
|
69
|
+
def.codegen_with_options(factory_only)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Marks a method within a `#[workflow_methods]` impl block as the initialization method.
|
|
73
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
74
|
+
#[proc_macro_attribute]
|
|
75
|
+
pub fn init(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
76
|
+
item
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Marks a method within a `#[workflow_methods]` impl block as the main run method.
|
|
80
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
81
|
+
#[proc_macro_attribute]
|
|
82
|
+
pub fn run(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
83
|
+
item
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Marks a method within a `#[workflow_methods]` impl block as a signal handler.
|
|
87
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
88
|
+
///
|
|
89
|
+
/// Supports an optional `name` parameter to override the signal name:
|
|
90
|
+
/// `#[signal(name = "my_signal")]`
|
|
91
|
+
#[proc_macro_attribute]
|
|
92
|
+
pub fn signal(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
93
|
+
item
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// Marks a method within a `#[workflow_methods]` impl block as a query handler.
|
|
97
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
98
|
+
///
|
|
99
|
+
/// Supports an optional `name` parameter to override the query name:
|
|
100
|
+
/// `#[query(name = "my_query")]`
|
|
101
|
+
#[proc_macro_attribute]
|
|
102
|
+
pub fn query(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
103
|
+
item
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Marks a method within a `#[workflow_methods]` impl block as an update handler.
|
|
107
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
108
|
+
///
|
|
109
|
+
/// Supports an optional `name` parameter to override the update name:
|
|
110
|
+
/// `#[update(name = "my_update")]`
|
|
111
|
+
#[proc_macro_attribute]
|
|
112
|
+
pub fn update(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
113
|
+
item
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// Marks a method within a `#[workflow_methods]` impl block as a validator for an update handler.
|
|
117
|
+
/// This attribute is processed by the `#[workflow_methods]` macro and should not be used standalone.
|
|
118
|
+
///
|
|
119
|
+
/// The parameter specifies which update this validator applies to:
|
|
120
|
+
/// `#[update_validator(my_update)]`
|
|
121
|
+
///
|
|
122
|
+
/// The validator method must:
|
|
123
|
+
/// - Take `&self` (not `&mut self`)
|
|
124
|
+
/// - Take `&WorkflowContextView` as the first parameter
|
|
125
|
+
/// - Take a reference to the update's input type as the second parameter
|
|
126
|
+
/// - Return `Result<(), Box<dyn std::error::Error + Send + Sync>>`
|
|
127
|
+
#[proc_macro_attribute]
|
|
128
|
+
pub fn update_validator(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
129
|
+
item
|
|
130
|
+
}
|
|
10
131
|
|
|
11
132
|
/// Parses a DSL for defining finite state machines, and produces code implementing the
|
|
12
133
|
/// [StateMachine](trait.StateMachine.html) trait.
|
|
13
134
|
///
|
|
14
135
|
/// An example state machine definition of a card reader for unlocking a door:
|
|
15
136
|
/// ```
|
|
16
|
-
/// use temporalio_macros::fsm;
|
|
17
137
|
/// use std::convert::Infallible;
|
|
18
138
|
/// use temporalio_common::fsm_trait::{StateMachine, TransitionResult};
|
|
139
|
+
/// use temporalio_macros::fsm;
|
|
19
140
|
///
|
|
20
141
|
/// fsm! {
|
|
21
142
|
/// name CardReader; command Commands; error Infallible; shared_state SharedState;
|
|
@@ -29,7 +150,7 @@ use syn::{
|
|
|
29
150
|
///
|
|
30
151
|
/// #[derive(Clone)]
|
|
31
152
|
/// pub struct SharedState {
|
|
32
|
-
/// last_id: Option<String
|
|
153
|
+
/// last_id: Option<String>,
|
|
33
154
|
/// }
|
|
34
155
|
///
|
|
35
156
|
/// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
@@ -61,8 +182,11 @@ use syn::{
|
|
|
61
182
|
/// }
|
|
62
183
|
///
|
|
63
184
|
/// impl Locked {
|
|
64
|
-
/// fn on_card_readable(
|
|
65
|
-
///
|
|
185
|
+
/// fn on_card_readable(
|
|
186
|
+
/// &self,
|
|
187
|
+
/// shared_dat: &mut SharedState,
|
|
188
|
+
/// data: CardData,
|
|
189
|
+
/// ) -> CardReaderTransition<ReadingCardOrLocked> {
|
|
66
190
|
/// match &shared_dat.last_id {
|
|
67
191
|
/// // Arbitrarily deny the same person entering twice in a row
|
|
68
192
|
/// Some(d) if d == &data => TransitionResult::ok(vec![], Locked {}.into()),
|
|
@@ -165,505 +289,7 @@ use syn::{
|
|
|
165
289
|
/// this case, `CardReaderTransition`.
|
|
166
290
|
#[proc_macro]
|
|
167
291
|
pub fn fsm(input: TokenStream) -> TokenStream {
|
|
168
|
-
let def: StateMachineDefinition =
|
|
292
|
+
let def: fsm_impl::StateMachineDefinition =
|
|
293
|
+
parse_macro_input!(input as fsm_impl::StateMachineDefinition);
|
|
169
294
|
def.codegen()
|
|
170
295
|
}
|
|
171
|
-
|
|
172
|
-
mod kw {
|
|
173
|
-
syn::custom_keyword!(name);
|
|
174
|
-
syn::custom_keyword!(command);
|
|
175
|
-
syn::custom_keyword!(error);
|
|
176
|
-
syn::custom_keyword!(shared);
|
|
177
|
-
syn::custom_keyword!(shared_state);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
struct StateMachineDefinition {
|
|
181
|
-
visibility: Visibility,
|
|
182
|
-
name: Ident,
|
|
183
|
-
shared_state_type: Option<Type>,
|
|
184
|
-
command_type: Ident,
|
|
185
|
-
error_type: Ident,
|
|
186
|
-
transitions: Vec<Transition>,
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
impl StateMachineDefinition {
|
|
190
|
-
fn is_final_state(&self, state: &Ident) -> bool {
|
|
191
|
-
// If no transitions go from this state, it's a final state.
|
|
192
|
-
!self.transitions.iter().any(|t| t.from == *state)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
impl Parse for StateMachineDefinition {
|
|
197
|
-
fn parse(input: ParseStream) -> Result<Self> {
|
|
198
|
-
// Parse visibility if present
|
|
199
|
-
let visibility = input.parse()?;
|
|
200
|
-
// parse the state machine name, command type, and error type
|
|
201
|
-
let (name, command_type, error_type, shared_state_type) = parse_machine_types(input)
|
|
202
|
-
.map_err(|mut e| {
|
|
203
|
-
e.combine(Error::new(
|
|
204
|
-
e.span(),
|
|
205
|
-
"The fsm definition should begin with `name MachineName; command CommandType; \
|
|
206
|
-
error ErrorType;` optionally followed by `shared_state SharedStateType;`",
|
|
207
|
-
));
|
|
208
|
-
e
|
|
209
|
-
})?;
|
|
210
|
-
// Then the state machine definition is simply a sequence of transitions separated by
|
|
211
|
-
// semicolons
|
|
212
|
-
let transitions = input.parse_terminated(Transition::parse, Token![;])?;
|
|
213
|
-
let transitions: Vec<_> = transitions.into_iter().collect();
|
|
214
|
-
// Check for and whine about any identical transitions. We do this here because preserving
|
|
215
|
-
// the order transitions were defined in is important, so simply collecting to a set is
|
|
216
|
-
// not ideal.
|
|
217
|
-
let trans_set: HashSet<_> = transitions.iter().collect();
|
|
218
|
-
if trans_set.len() != transitions.len() {
|
|
219
|
-
return Err(Error::new(
|
|
220
|
-
input.span(),
|
|
221
|
-
"Duplicate transitions are not allowed!",
|
|
222
|
-
));
|
|
223
|
-
}
|
|
224
|
-
Ok(Self {
|
|
225
|
-
visibility,
|
|
226
|
-
name,
|
|
227
|
-
shared_state_type,
|
|
228
|
-
command_type,
|
|
229
|
-
error_type,
|
|
230
|
-
transitions,
|
|
231
|
-
})
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
fn parse_machine_types(input: ParseStream) -> Result<(Ident, Ident, Ident, Option<Type>)> {
|
|
236
|
-
let _: kw::name = input.parse()?;
|
|
237
|
-
let name: Ident = input.parse()?;
|
|
238
|
-
input.parse::<Token![;]>()?;
|
|
239
|
-
|
|
240
|
-
let _: kw::command = input.parse()?;
|
|
241
|
-
let command_type: Ident = input.parse()?;
|
|
242
|
-
input.parse::<Token![;]>()?;
|
|
243
|
-
|
|
244
|
-
let _: kw::error = input.parse()?;
|
|
245
|
-
let error_type: Ident = input.parse()?;
|
|
246
|
-
input.parse::<Token![;]>()?;
|
|
247
|
-
|
|
248
|
-
let shared_state_type: Option<Type> = if input.peek(kw::shared_state) {
|
|
249
|
-
let _: kw::shared_state = input.parse()?;
|
|
250
|
-
let typep = input.parse()?;
|
|
251
|
-
input.parse::<Token![;]>()?;
|
|
252
|
-
Some(typep)
|
|
253
|
-
} else {
|
|
254
|
-
None
|
|
255
|
-
};
|
|
256
|
-
Ok((name, command_type, error_type, shared_state_type))
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
260
|
-
struct Transition {
|
|
261
|
-
from: Ident,
|
|
262
|
-
to: Vec<Ident>,
|
|
263
|
-
event: Variant,
|
|
264
|
-
handler: Option<Ident>,
|
|
265
|
-
mutates_shared: bool,
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
impl Parse for Transition {
|
|
269
|
-
fn parse(input: ParseStream) -> Result<Self> {
|
|
270
|
-
// Parse the initial state name
|
|
271
|
-
let from: Ident = input.parse()?;
|
|
272
|
-
// Parse at least one dash
|
|
273
|
-
input.parse::<Token![-]>()?;
|
|
274
|
-
while input.peek(Token![-]) {
|
|
275
|
-
input.parse::<Token![-]>()?;
|
|
276
|
-
}
|
|
277
|
-
// Parse transition information inside parens
|
|
278
|
-
let transition_info;
|
|
279
|
-
parenthesized!(transition_info in input);
|
|
280
|
-
// Get the event variant definition
|
|
281
|
-
let event: Variant = transition_info.parse()?;
|
|
282
|
-
// Reject non-unit or single-item-tuple variants
|
|
283
|
-
match &event.fields {
|
|
284
|
-
Fields::Named(_) => {
|
|
285
|
-
return Err(Error::new(
|
|
286
|
-
event.span(),
|
|
287
|
-
"Struct variants are not supported for events",
|
|
288
|
-
));
|
|
289
|
-
}
|
|
290
|
-
Fields::Unnamed(uf) => {
|
|
291
|
-
if uf.unnamed.len() != 1 {
|
|
292
|
-
return Err(Error::new(
|
|
293
|
-
event.span(),
|
|
294
|
-
"Only tuple variants with exactly one item are supported for events",
|
|
295
|
-
));
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
Fields::Unit => {}
|
|
299
|
-
}
|
|
300
|
-
// Check if there is an event handler, and parse it
|
|
301
|
-
let (mutates_shared, handler) = if transition_info.peek(Token![,]) {
|
|
302
|
-
transition_info.parse::<Token![,]>()?;
|
|
303
|
-
// Check for mut keyword signifying handler wants to mutate shared state
|
|
304
|
-
let mutates = if transition_info.peek(kw::shared) {
|
|
305
|
-
transition_info.parse::<kw::shared>()?;
|
|
306
|
-
true
|
|
307
|
-
} else {
|
|
308
|
-
false
|
|
309
|
-
};
|
|
310
|
-
(mutates, Some(transition_info.parse()?))
|
|
311
|
-
} else {
|
|
312
|
-
(false, None)
|
|
313
|
-
};
|
|
314
|
-
// Parse at least one dash followed by the "arrow"
|
|
315
|
-
input.parse::<Token![-]>()?;
|
|
316
|
-
while input.peek(Token![-]) {
|
|
317
|
-
input.parse::<Token![-]>()?;
|
|
318
|
-
}
|
|
319
|
-
input.parse::<Token![>]>()?;
|
|
320
|
-
// Parse the destination state
|
|
321
|
-
let to: Ident = input.parse()?;
|
|
322
|
-
|
|
323
|
-
Ok(Self {
|
|
324
|
-
from,
|
|
325
|
-
event,
|
|
326
|
-
handler,
|
|
327
|
-
to: vec![to],
|
|
328
|
-
mutates_shared,
|
|
329
|
-
})
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
impl StateMachineDefinition {
|
|
334
|
-
fn codegen(&self) -> TokenStream {
|
|
335
|
-
let visibility = self.visibility.clone();
|
|
336
|
-
// First extract all of the states into a set, and build the enum's insides
|
|
337
|
-
let states = self.all_states();
|
|
338
|
-
let state_variants = states.iter().map(|s| {
|
|
339
|
-
let statestr = s.to_string();
|
|
340
|
-
quote! {
|
|
341
|
-
#[display(#statestr)]
|
|
342
|
-
#s(#s)
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
let name = &self.name;
|
|
346
|
-
let name_str = &self.name.to_string();
|
|
347
|
-
|
|
348
|
-
let transition_result_name = Ident::new(&format!("{name}Transition"), name.span());
|
|
349
|
-
let transition_type_alias = quote! {
|
|
350
|
-
type #transition_result_name<Ds, Sm = #name> = TransitionResult<Sm, Ds>;
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
let state_enum_name = Ident::new(&format!("{name}State"), name.span());
|
|
354
|
-
// If user has not defined any shared state, use the unit type.
|
|
355
|
-
let shared_state_type = self
|
|
356
|
-
.shared_state_type
|
|
357
|
-
.clone()
|
|
358
|
-
.unwrap_or_else(|| syn::parse_str("()").unwrap());
|
|
359
|
-
let machine_struct = quote! {
|
|
360
|
-
#[derive(Clone)]
|
|
361
|
-
#visibility struct #name {
|
|
362
|
-
state: ::core::option::Option<#state_enum_name>,
|
|
363
|
-
shared_state: #shared_state_type
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
let states_enum = quote! {
|
|
367
|
-
#[derive(::derive_more::From, Clone, ::derive_more::Display)]
|
|
368
|
-
#visibility enum #state_enum_name {
|
|
369
|
-
#(#state_variants),*
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
let state_is_final_match_arms = states.iter().map(|s| {
|
|
373
|
-
let val = if self.is_final_state(s) {
|
|
374
|
-
quote! { true }
|
|
375
|
-
} else {
|
|
376
|
-
quote! { false }
|
|
377
|
-
};
|
|
378
|
-
quote! { #state_enum_name::#s(_) => #val }
|
|
379
|
-
});
|
|
380
|
-
let states_enum_impl = quote! {
|
|
381
|
-
impl #state_enum_name {
|
|
382
|
-
fn is_final(&self) -> bool {
|
|
383
|
-
match self {
|
|
384
|
-
#(#state_is_final_match_arms),*
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
// Build the events enum
|
|
391
|
-
let events: HashSet<Variant> = self.transitions.iter().map(|t| t.event.clone()).collect();
|
|
392
|
-
let events_enum_name = Ident::new(&format!("{name}Events"), name.span());
|
|
393
|
-
let events: Vec<_> = events
|
|
394
|
-
.into_iter()
|
|
395
|
-
.map(|v| {
|
|
396
|
-
let vname = v.ident.to_string();
|
|
397
|
-
quote! {
|
|
398
|
-
#[display(#vname)]
|
|
399
|
-
#v
|
|
400
|
-
}
|
|
401
|
-
})
|
|
402
|
-
.collect();
|
|
403
|
-
let events_enum = quote! {
|
|
404
|
-
#[derive(::derive_more::Display)]
|
|
405
|
-
#visibility enum #events_enum_name {
|
|
406
|
-
#(#events),*
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
// Construct the trait implementation
|
|
411
|
-
let cmd_type = &self.command_type;
|
|
412
|
-
let err_type = &self.error_type;
|
|
413
|
-
let mut statemap: HashMap<Ident, Vec<Transition>> = HashMap::new();
|
|
414
|
-
for t in &self.transitions {
|
|
415
|
-
statemap
|
|
416
|
-
.entry(t.from.clone())
|
|
417
|
-
.and_modify(|v| v.push(t.clone()))
|
|
418
|
-
.or_insert_with(|| vec![t.clone()]);
|
|
419
|
-
}
|
|
420
|
-
// Add any states without any transitions to the map
|
|
421
|
-
for s in &states {
|
|
422
|
-
if !statemap.contains_key(s) {
|
|
423
|
-
statemap.insert(s.clone(), vec![]);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
let transition_result_transform = quote! {
|
|
427
|
-
match res.into_cmd_result() {
|
|
428
|
-
Ok((cmds, state)) => {
|
|
429
|
-
self.state = Some(state);
|
|
430
|
-
Ok(cmds)
|
|
431
|
-
}
|
|
432
|
-
Err(e) => Err(e)
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
let mut multi_dest_enums = vec![];
|
|
436
|
-
let mut multi_dest_enum_names = HashSet::new();
|
|
437
|
-
let state_branches: Vec<_> = statemap.into_iter().map(|(from, transitions)| {
|
|
438
|
-
let occupied_current_state = quote! { Some(#state_enum_name::#from(state_data)) };
|
|
439
|
-
// Merge transition dest states with the same handler
|
|
440
|
-
let transitions = merge_transition_dests(transitions);
|
|
441
|
-
let event_branches = transitions
|
|
442
|
-
.into_iter()
|
|
443
|
-
.map(|ts| {
|
|
444
|
-
let ev_variant = &ts.event.ident;
|
|
445
|
-
if let Some(ts_fn) = ts.handler.clone() {
|
|
446
|
-
let span = ts_fn.span();
|
|
447
|
-
let trans_type = match ts.to.as_slice() {
|
|
448
|
-
[] => unreachable!("There will be at least one dest state in transitions"),
|
|
449
|
-
[one_to] => quote! {
|
|
450
|
-
#transition_result_name<#one_to>
|
|
451
|
-
},
|
|
452
|
-
multi_dests => {
|
|
453
|
-
let string_dests: Vec<_> = multi_dests.iter()
|
|
454
|
-
.map(ToString::to_string).collect();
|
|
455
|
-
let enum_ident = Ident::new(&string_dests.join("Or"),
|
|
456
|
-
multi_dests[0].span());
|
|
457
|
-
let multi_dest_enum = quote! {
|
|
458
|
-
#[derive(::derive_more::From)]
|
|
459
|
-
#visibility enum #enum_ident {
|
|
460
|
-
#(#multi_dests(#multi_dests)),*
|
|
461
|
-
}
|
|
462
|
-
impl ::core::convert::From<#enum_ident> for #state_enum_name {
|
|
463
|
-
fn from(v: #enum_ident) -> Self {
|
|
464
|
-
match v {
|
|
465
|
-
#( #enum_ident::#multi_dests(sv) =>
|
|
466
|
-
Self::#multi_dests(sv) ),*
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
// Deduplicate; two different events may each result in a transition
|
|
472
|
-
// set with the same set of dest states
|
|
473
|
-
if multi_dest_enum_names.insert(enum_ident.clone()) {
|
|
474
|
-
multi_dest_enums.push(multi_dest_enum);
|
|
475
|
-
}
|
|
476
|
-
quote! {
|
|
477
|
-
#transition_result_name<#enum_ident>
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
};
|
|
481
|
-
match ts.event.fields {
|
|
482
|
-
Fields::Unnamed(_) => {
|
|
483
|
-
let arglist = if ts.mutates_shared {
|
|
484
|
-
quote! {&mut self.shared_state, val}
|
|
485
|
-
} else {
|
|
486
|
-
quote! {val}
|
|
487
|
-
};
|
|
488
|
-
quote_spanned! { span =>
|
|
489
|
-
#events_enum_name::#ev_variant(val) => {
|
|
490
|
-
let res: #trans_type = state_data.#ts_fn(#arglist);
|
|
491
|
-
#transition_result_transform
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
Fields::Unit => {
|
|
496
|
-
let arglist = if ts.mutates_shared {
|
|
497
|
-
quote! {&mut self.shared_state}
|
|
498
|
-
} else {
|
|
499
|
-
quote! {}
|
|
500
|
-
};
|
|
501
|
-
quote_spanned! { span =>
|
|
502
|
-
#events_enum_name::#ev_variant => {
|
|
503
|
-
let res: #trans_type = state_data.#ts_fn(#arglist);
|
|
504
|
-
#transition_result_transform
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
Fields::Named(_) => unreachable!(),
|
|
509
|
-
}
|
|
510
|
-
} else {
|
|
511
|
-
// If events do not have a handler, attempt to construct the next state
|
|
512
|
-
// using `Default`.
|
|
513
|
-
if let [new_state] = ts.to.as_slice() {
|
|
514
|
-
let span = new_state.span();
|
|
515
|
-
let default_trans = quote_spanned! { span =>
|
|
516
|
-
let res = TransitionResult::<Self, #new_state>::from::<#from>(state_data);
|
|
517
|
-
#transition_result_transform
|
|
518
|
-
};
|
|
519
|
-
let span = ts.event.span();
|
|
520
|
-
match ts.event.fields {
|
|
521
|
-
Fields::Unnamed(_) => quote_spanned! { span =>
|
|
522
|
-
#events_enum_name::#ev_variant(_val) => {
|
|
523
|
-
#default_trans
|
|
524
|
-
}
|
|
525
|
-
},
|
|
526
|
-
Fields::Unit => quote_spanned! { span =>
|
|
527
|
-
#events_enum_name::#ev_variant => {
|
|
528
|
-
#default_trans
|
|
529
|
-
}
|
|
530
|
-
},
|
|
531
|
-
Fields::Named(_) => unreachable!(),
|
|
532
|
-
}
|
|
533
|
-
} else {
|
|
534
|
-
unreachable!("It should be impossible to have more than one dest state \
|
|
535
|
-
in no-handler transitions")
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
})
|
|
539
|
-
// Since most states won't handle every possible event, return an error to that
|
|
540
|
-
// effect
|
|
541
|
-
.chain(std::iter::once(
|
|
542
|
-
quote! { _ => {
|
|
543
|
-
// Restore state in event the transition doesn't match
|
|
544
|
-
self.state = #occupied_current_state;
|
|
545
|
-
return Err(::temporalio_common::fsm_trait::MachineError::InvalidTransition)
|
|
546
|
-
} },
|
|
547
|
-
));
|
|
548
|
-
quote! {
|
|
549
|
-
#occupied_current_state => match event {
|
|
550
|
-
#(#event_branches),*
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}).chain(std::iter::once(
|
|
554
|
-
quote! {
|
|
555
|
-
None => Err(::temporalio_common::fsm_trait::MachineError::InvalidTransition)
|
|
556
|
-
}
|
|
557
|
-
)).collect();
|
|
558
|
-
|
|
559
|
-
let viz_str = self.visualize();
|
|
560
|
-
|
|
561
|
-
let trait_impl = quote! {
|
|
562
|
-
impl ::temporalio_common::fsm_trait::StateMachine for #name {
|
|
563
|
-
type Error = #err_type;
|
|
564
|
-
type State = #state_enum_name;
|
|
565
|
-
type SharedState = #shared_state_type;
|
|
566
|
-
type Event = #events_enum_name;
|
|
567
|
-
type Command = #cmd_type;
|
|
568
|
-
|
|
569
|
-
fn name(&self) -> &str {
|
|
570
|
-
#name_str
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
fn on_event(&mut self, event: #events_enum_name)
|
|
574
|
-
-> ::core::result::Result<::std::vec::Vec<Self::Command>,
|
|
575
|
-
::temporalio_common::fsm_trait::MachineError<Self::Error>> {
|
|
576
|
-
let taken_state = self.state.take();
|
|
577
|
-
match taken_state {
|
|
578
|
-
#(#state_branches),*
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
fn state(&self) -> &Self::State {
|
|
583
|
-
self.state.as_ref().unwrap()
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
fn shared_state(&self) -> &Self::SharedState{
|
|
587
|
-
&self.shared_state
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
fn has_reached_final_state(&self) -> bool {
|
|
591
|
-
self.state.as_ref().unwrap().is_final()
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
fn from_parts(state: Self::State, shared: Self::SharedState) -> Self {
|
|
595
|
-
Self { shared_state: shared, state: Some(state) }
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
fn visualizer() -> &'static str {
|
|
599
|
-
#viz_str
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
};
|
|
603
|
-
|
|
604
|
-
let output = quote! {
|
|
605
|
-
#transition_type_alias
|
|
606
|
-
#machine_struct
|
|
607
|
-
#states_enum
|
|
608
|
-
#(#multi_dest_enums)*
|
|
609
|
-
#states_enum_impl
|
|
610
|
-
#events_enum
|
|
611
|
-
#trait_impl
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
TokenStream::from(output)
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
fn all_states(&self) -> HashSet<Ident> {
|
|
618
|
-
self.transitions
|
|
619
|
-
.iter()
|
|
620
|
-
.flat_map(|t| {
|
|
621
|
-
let mut states = t.to.clone();
|
|
622
|
-
states.push(t.from.clone());
|
|
623
|
-
states
|
|
624
|
-
})
|
|
625
|
-
.collect()
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
fn visualize(&self) -> String {
|
|
629
|
-
let transitions: Vec<String> = self
|
|
630
|
-
.transitions
|
|
631
|
-
.iter()
|
|
632
|
-
.flat_map(|t| {
|
|
633
|
-
t.to.iter()
|
|
634
|
-
.map(move |d| format!("{} --> {}: {}", t.from, d, t.event.ident))
|
|
635
|
-
})
|
|
636
|
-
// Add all final state transitions
|
|
637
|
-
.chain(
|
|
638
|
-
self.all_states()
|
|
639
|
-
.iter()
|
|
640
|
-
.filter(|s| self.is_final_state(s))
|
|
641
|
-
.map(|s| format!("{s} --> [*]")),
|
|
642
|
-
)
|
|
643
|
-
.collect();
|
|
644
|
-
let transitions = transitions.join("\n");
|
|
645
|
-
format!("@startuml\n{transitions}\n@enduml")
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/// Merge transition's dest state lists for those with the same from state & handler
|
|
650
|
-
fn merge_transition_dests(transitions: Vec<Transition>) -> Vec<Transition> {
|
|
651
|
-
let mut map = HashMap::<_, Transition>::new();
|
|
652
|
-
for t in transitions {
|
|
653
|
-
// We want to use the transition sans-destinations as the key
|
|
654
|
-
let without_dests = {
|
|
655
|
-
let mut wd = t.clone();
|
|
656
|
-
wd.to = vec![];
|
|
657
|
-
wd
|
|
658
|
-
};
|
|
659
|
-
match map.entry(without_dests) {
|
|
660
|
-
Entry::Occupied(mut e) => {
|
|
661
|
-
e.get_mut().to.extend(t.to.into_iter());
|
|
662
|
-
}
|
|
663
|
-
Entry::Vacant(v) => {
|
|
664
|
-
v.insert(t);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
map.into_values().collect()
|
|
669
|
-
}
|