temporalio 0.0.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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/bridge/Cargo.lock +2865 -0
- data/bridge/Cargo.toml +26 -0
- data/bridge/sdk-core/ARCHITECTURE.md +76 -0
- data/bridge/sdk-core/Cargo.lock +2606 -0
- data/bridge/sdk-core/Cargo.toml +2 -0
- data/bridge/sdk-core/LICENSE.txt +23 -0
- data/bridge/sdk-core/README.md +107 -0
- data/bridge/sdk-core/arch_docs/diagrams/README.md +10 -0
- data/bridge/sdk-core/arch_docs/diagrams/sticky_queues.puml +40 -0
- data/bridge/sdk-core/arch_docs/diagrams/workflow_internals.svg +1 -0
- data/bridge/sdk-core/arch_docs/sticky_queues.md +51 -0
- data/bridge/sdk-core/bridge-ffi/Cargo.toml +24 -0
- data/bridge/sdk-core/bridge-ffi/LICENSE.txt +23 -0
- data/bridge/sdk-core/bridge-ffi/build.rs +25 -0
- data/bridge/sdk-core/bridge-ffi/include/sdk-core-bridge.h +249 -0
- data/bridge/sdk-core/bridge-ffi/src/lib.rs +825 -0
- data/bridge/sdk-core/bridge-ffi/src/wrappers.rs +211 -0
- data/bridge/sdk-core/client/Cargo.toml +40 -0
- data/bridge/sdk-core/client/LICENSE.txt +23 -0
- data/bridge/sdk-core/client/src/lib.rs +1294 -0
- data/bridge/sdk-core/client/src/metrics.rs +165 -0
- data/bridge/sdk-core/client/src/raw.rs +931 -0
- data/bridge/sdk-core/client/src/retry.rs +674 -0
- data/bridge/sdk-core/client/src/workflow_handle/mod.rs +185 -0
- data/bridge/sdk-core/core/Cargo.toml +116 -0
- data/bridge/sdk-core/core/LICENSE.txt +23 -0
- data/bridge/sdk-core/core/benches/workflow_replay.rs +73 -0
- data/bridge/sdk-core/core/src/abstractions.rs +166 -0
- data/bridge/sdk-core/core/src/core_tests/activity_tasks.rs +911 -0
- data/bridge/sdk-core/core/src/core_tests/child_workflows.rs +221 -0
- data/bridge/sdk-core/core/src/core_tests/determinism.rs +107 -0
- data/bridge/sdk-core/core/src/core_tests/local_activities.rs +515 -0
- data/bridge/sdk-core/core/src/core_tests/mod.rs +100 -0
- data/bridge/sdk-core/core/src/core_tests/queries.rs +736 -0
- data/bridge/sdk-core/core/src/core_tests/replay_flag.rs +65 -0
- data/bridge/sdk-core/core/src/core_tests/workers.rs +259 -0
- data/bridge/sdk-core/core/src/core_tests/workflow_cancels.rs +124 -0
- data/bridge/sdk-core/core/src/core_tests/workflow_tasks.rs +2070 -0
- data/bridge/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
- data/bridge/sdk-core/core/src/lib.rs +175 -0
- data/bridge/sdk-core/core/src/log_export.rs +62 -0
- data/bridge/sdk-core/core/src/pollers/mod.rs +54 -0
- data/bridge/sdk-core/core/src/pollers/poll_buffer.rs +297 -0
- data/bridge/sdk-core/core/src/protosext/mod.rs +428 -0
- data/bridge/sdk-core/core/src/replay/mod.rs +71 -0
- data/bridge/sdk-core/core/src/retry_logic.rs +202 -0
- data/bridge/sdk-core/core/src/telemetry/metrics.rs +383 -0
- data/bridge/sdk-core/core/src/telemetry/mod.rs +412 -0
- data/bridge/sdk-core/core/src/telemetry/prometheus_server.rs +77 -0
- data/bridge/sdk-core/core/src/test_help/mod.rs +875 -0
- data/bridge/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +580 -0
- data/bridge/sdk-core/core/src/worker/activities/local_activities.rs +1042 -0
- data/bridge/sdk-core/core/src/worker/activities.rs +464 -0
- data/bridge/sdk-core/core/src/worker/client/mocks.rs +87 -0
- data/bridge/sdk-core/core/src/worker/client.rs +347 -0
- data/bridge/sdk-core/core/src/worker/mod.rs +566 -0
- data/bridge/sdk-core/core/src/worker/workflow/bridge.rs +37 -0
- data/bridge/sdk-core/core/src/worker/workflow/driven_workflow.rs +110 -0
- data/bridge/sdk-core/core/src/worker/workflow/history_update.rs +458 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/activity_state_machine.rs +911 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +298 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/cancel_workflow_state_machine.rs +171 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +860 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/complete_workflow_state_machine.rs +140 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/continue_as_new_workflow_state_machine.rs +161 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/fail_workflow_state_machine.rs +133 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/local_activity_state_machine.rs +1448 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/mod.rs +342 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/mutable_side_effect_state_machine.rs +127 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/patch_state_machine.rs +712 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/side_effect_state_machine.rs +71 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +443 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/timer_state_machine.rs +439 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/transition_coverage.rs +169 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +246 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines/local_acts.rs +96 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +1184 -0
- data/bridge/sdk-core/core/src/worker/workflow/machines/workflow_task_state_machine.rs +277 -0
- data/bridge/sdk-core/core/src/worker/workflow/managed_run/managed_wf_test.rs +198 -0
- data/bridge/sdk-core/core/src/worker/workflow/managed_run.rs +647 -0
- data/bridge/sdk-core/core/src/worker/workflow/mod.rs +1143 -0
- data/bridge/sdk-core/core/src/worker/workflow/run_cache.rs +145 -0
- data/bridge/sdk-core/core/src/worker/workflow/wft_poller.rs +88 -0
- data/bridge/sdk-core/core/src/worker/workflow/workflow_stream.rs +940 -0
- data/bridge/sdk-core/core-api/Cargo.toml +31 -0
- data/bridge/sdk-core/core-api/LICENSE.txt +23 -0
- data/bridge/sdk-core/core-api/src/errors.rs +95 -0
- data/bridge/sdk-core/core-api/src/lib.rs +151 -0
- data/bridge/sdk-core/core-api/src/worker.rs +135 -0
- data/bridge/sdk-core/etc/deps.svg +187 -0
- data/bridge/sdk-core/etc/dynamic-config.yaml +2 -0
- data/bridge/sdk-core/etc/otel-collector-config.yaml +36 -0
- data/bridge/sdk-core/etc/prometheus.yaml +6 -0
- data/bridge/sdk-core/fsm/Cargo.toml +18 -0
- data/bridge/sdk-core/fsm/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/README.md +3 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/Cargo.toml +27 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/src/lib.rs +647 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/progress.rs +8 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.rs +18 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dupe_transitions_fail.stderr +12 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/dynamic_dest_pass.rs +41 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.rs +14 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/forgot_name_fail.stderr +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_arg_pass.rs +32 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/handler_pass.rs +31 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/medium_complex_pass.rs +46 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +29 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +12 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/simple_pass.rs +32 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.rs +18 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/struct_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +11 -0
- data/bridge/sdk-core/fsm/rustfsm_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.stderr +5 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/Cargo.toml +14 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/LICENSE.txt +23 -0
- data/bridge/sdk-core/fsm/rustfsm_trait/src/lib.rs +249 -0
- data/bridge/sdk-core/fsm/src/lib.rs +2 -0
- data/bridge/sdk-core/histories/fail_wf_task.bin +0 -0
- data/bridge/sdk-core/histories/timer_workflow_history.bin +0 -0
- data/bridge/sdk-core/integ-with-otel.sh +7 -0
- data/bridge/sdk-core/protos/api_upstream/README.md +9 -0
- data/bridge/sdk-core/protos/api_upstream/api-linter.yaml +40 -0
- data/bridge/sdk-core/protos/api_upstream/buf.yaml +12 -0
- data/bridge/sdk-core/protos/api_upstream/dependencies/gogoproto/gogo.proto +141 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/cluster/v1/message.proto +83 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +259 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/common/v1/message.proto +112 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/cluster.proto +40 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +57 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/common.proto +55 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +168 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +97 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +51 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/query.proto +50 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/reset.proto +41 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/schedule.proto +60 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +59 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +122 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +108 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +114 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/filter/v1/message.proto +56 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +751 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/namespace/v1/message.proto +97 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +161 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +99 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/query/v1/message.proto +61 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +55 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/schedule/v1/message.proto +300 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +108 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/version/v1/message.proto +59 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +145 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +1124 -0
- data/bridge/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +401 -0
- data/bridge/sdk-core/protos/grpc/health/v1/health.proto +63 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_result/activity_result.proto +78 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/activity_task/activity_task.proto +79 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +210 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/child_workflow/child_workflow.proto +77 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/common/common.proto +15 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +30 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/external_data/external_data.proto +30 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +261 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +297 -0
- data/bridge/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +29 -0
- data/bridge/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
- data/bridge/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
- data/bridge/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
- data/bridge/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
- data/bridge/sdk-core/rustfmt.toml +1 -0
- data/bridge/sdk-core/sdk/Cargo.toml +47 -0
- data/bridge/sdk-core/sdk/LICENSE.txt +23 -0
- data/bridge/sdk-core/sdk/src/activity_context.rs +230 -0
- data/bridge/sdk-core/sdk/src/app_data.rs +37 -0
- data/bridge/sdk-core/sdk/src/conversions.rs +8 -0
- data/bridge/sdk-core/sdk/src/interceptors.rs +17 -0
- data/bridge/sdk-core/sdk/src/lib.rs +792 -0
- data/bridge/sdk-core/sdk/src/payload_converter.rs +11 -0
- data/bridge/sdk-core/sdk/src/workflow_context/options.rs +295 -0
- data/bridge/sdk-core/sdk/src/workflow_context.rs +683 -0
- data/bridge/sdk-core/sdk/src/workflow_future.rs +503 -0
- data/bridge/sdk-core/sdk-core-protos/Cargo.toml +30 -0
- data/bridge/sdk-core/sdk-core-protos/LICENSE.txt +23 -0
- data/bridge/sdk-core/sdk-core-protos/build.rs +108 -0
- data/bridge/sdk-core/sdk-core-protos/src/constants.rs +7 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_builder.rs +497 -0
- data/bridge/sdk-core/sdk-core-protos/src/history_info.rs +230 -0
- data/bridge/sdk-core/sdk-core-protos/src/lib.rs +1910 -0
- data/bridge/sdk-core/sdk-core-protos/src/task_token.rs +38 -0
- data/bridge/sdk-core/sdk-core-protos/src/utilities.rs +14 -0
- data/bridge/sdk-core/test-utils/Cargo.toml +35 -0
- data/bridge/sdk-core/test-utils/src/canned_histories.rs +1579 -0
- data/bridge/sdk-core/test-utils/src/histfetch.rs +28 -0
- data/bridge/sdk-core/test-utils/src/lib.rs +598 -0
- data/bridge/sdk-core/tests/integ_tests/client_tests.rs +36 -0
- data/bridge/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
- data/bridge/sdk-core/tests/integ_tests/heartbeat_tests.rs +218 -0
- data/bridge/sdk-core/tests/integ_tests/polling_tests.rs +146 -0
- data/bridge/sdk-core/tests/integ_tests/queries_tests.rs +437 -0
- data/bridge/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/activities.rs +878 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/appdata_propagation.rs +61 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +59 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +58 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +50 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +60 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +54 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +634 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/patches.rs +113 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/replay.rs +137 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/resets.rs +93 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/signals.rs +167 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +99 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/timers.rs +131 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +75 -0
- data/bridge/sdk-core/tests/integ_tests/workflow_tests.rs +587 -0
- data/bridge/sdk-core/tests/load_tests.rs +191 -0
- data/bridge/sdk-core/tests/main.rs +111 -0
- data/bridge/sdk-core/tests/runner.rs +93 -0
- data/bridge/src/connection.rs +167 -0
- data/bridge/src/lib.rs +180 -0
- data/bridge/src/runtime.rs +47 -0
- data/bridge/src/worker.rs +73 -0
- data/ext/Rakefile +9 -0
- data/lib/bridge.so +0 -0
- data/lib/gen/dependencies/gogoproto/gogo_pb.rb +14 -0
- data/lib/gen/temporal/api/batch/v1/message_pb.rb +48 -0
- data/lib/gen/temporal/api/cluster/v1/message_pb.rb +67 -0
- data/lib/gen/temporal/api/command/v1/message_pb.rb +166 -0
- data/lib/gen/temporal/api/common/v1/message_pb.rb +69 -0
- data/lib/gen/temporal/api/enums/v1/batch_operation_pb.rb +32 -0
- data/lib/gen/temporal/api/enums/v1/cluster_pb.rb +26 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +37 -0
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +41 -0
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +67 -0
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +71 -0
- data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +37 -0
- data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
- data/lib/gen/temporal/api/enums/v1/reset_pb.rb +24 -0
- data/lib/gen/temporal/api/enums/v1/schedule_pb.rb +28 -0
- data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
- data/lib/gen/temporal/api/enums/v1/update_pb.rb +28 -0
- data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +89 -0
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +84 -0
- data/lib/gen/temporal/api/failure/v1/message_pb.rb +83 -0
- data/lib/gen/temporal/api/filter/v1/message_pb.rb +40 -0
- data/lib/gen/temporal/api/history/v1/message_pb.rb +489 -0
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +63 -0
- data/lib/gen/temporal/api/operatorservice/v1/request_response_pb.rb +125 -0
- data/lib/gen/temporal/api/operatorservice/v1/service_pb.rb +20 -0
- data/lib/gen/temporal/api/query/v1/message_pb.rb +38 -0
- data/lib/gen/temporal/api/replication/v1/message_pb.rb +37 -0
- data/lib/gen/temporal/api/schedule/v1/message_pb.rb +128 -0
- data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +73 -0
- data/lib/gen/temporal/api/update/v1/message_pb.rb +26 -0
- data/lib/gen/temporal/api/version/v1/message_pb.rb +41 -0
- data/lib/gen/temporal/api/workflow/v1/message_pb.rb +110 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +771 -0
- data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +20 -0
- data/lib/gen/temporal/sdk/core/activity_result/activity_result_pb.rb +58 -0
- data/lib/gen/temporal/sdk/core/activity_task/activity_task_pb.rb +57 -0
- data/lib/gen/temporal/sdk/core/bridge/bridge_pb.rb +222 -0
- data/lib/gen/temporal/sdk/core/child_workflow/child_workflow_pb.rb +57 -0
- data/lib/gen/temporal/sdk/core/common/common_pb.rb +22 -0
- data/lib/gen/temporal/sdk/core/core_interface_pb.rb +34 -0
- data/lib/gen/temporal/sdk/core/external_data/external_data_pb.rb +27 -0
- data/lib/gen/temporal/sdk/core/workflow_activation/workflow_activation_pb.rb +164 -0
- data/lib/gen/temporal/sdk/core/workflow_commands/workflow_commands_pb.rb +192 -0
- data/lib/gen/temporal/sdk/core/workflow_completion/workflow_completion_pb.rb +34 -0
- data/lib/temporal/bridge.rb +14 -0
- data/lib/temporal/client/implementation.rb +339 -0
- data/lib/temporal/client/workflow_handle.rb +243 -0
- data/lib/temporal/client.rb +144 -0
- data/lib/temporal/connection.rb +736 -0
- data/lib/temporal/data_converter.rb +150 -0
- data/lib/temporal/error/failure.rb +194 -0
- data/lib/temporal/error/workflow_failure.rb +17 -0
- data/lib/temporal/errors.rb +22 -0
- data/lib/temporal/failure_converter/base.rb +26 -0
- data/lib/temporal/failure_converter/basic.rb +313 -0
- data/lib/temporal/failure_converter.rb +8 -0
- data/lib/temporal/interceptor/chain.rb +27 -0
- data/lib/temporal/interceptor/client.rb +102 -0
- data/lib/temporal/payload_codec/base.rb +32 -0
- data/lib/temporal/payload_converter/base.rb +24 -0
- data/lib/temporal/payload_converter/bytes.rb +26 -0
- data/lib/temporal/payload_converter/composite.rb +47 -0
- data/lib/temporal/payload_converter/encoding_base.rb +35 -0
- data/lib/temporal/payload_converter/json.rb +25 -0
- data/lib/temporal/payload_converter/nil.rb +25 -0
- data/lib/temporal/payload_converter.rb +14 -0
- data/lib/temporal/retry_policy.rb +82 -0
- data/lib/temporal/retry_state.rb +35 -0
- data/lib/temporal/runtime.rb +22 -0
- data/lib/temporal/timeout_type.rb +29 -0
- data/lib/temporal/version.rb +3 -0
- data/lib/temporal/workflow/execution_info.rb +54 -0
- data/lib/temporal/workflow/execution_status.rb +36 -0
- data/lib/temporal/workflow/id_reuse_policy.rb +36 -0
- data/lib/temporal/workflow/query_reject_condition.rb +33 -0
- data/lib/temporal.rb +8 -0
- data/lib/temporalio.rb +3 -0
- data/lib/thermite_patch.rb +23 -0
- data/temporalio.gemspec +41 -0
- metadata +583 -0
@@ -0,0 +1,647 @@
|
|
1
|
+
use proc_macro::TokenStream;
|
2
|
+
use quote::{quote, quote_spanned};
|
3
|
+
use std::collections::{hash_map::Entry, HashMap, HashSet};
|
4
|
+
use syn::{
|
5
|
+
parenthesized,
|
6
|
+
parse::{Parse, ParseStream, Result},
|
7
|
+
parse_macro_input,
|
8
|
+
punctuated::Punctuated,
|
9
|
+
spanned::Spanned,
|
10
|
+
Error, Fields, Ident, Token, Type, Variant, Visibility,
|
11
|
+
};
|
12
|
+
|
13
|
+
/// Parses a DSL for defining finite state machines, and produces code implementing the
|
14
|
+
/// [StateMachine](trait.StateMachine.html) trait.
|
15
|
+
///
|
16
|
+
/// An example state machine definition of a card reader for unlocking a door:
|
17
|
+
/// ```
|
18
|
+
/// # extern crate rustfsm_trait as rustfsm;
|
19
|
+
/// use rustfsm_procmacro::fsm;
|
20
|
+
/// use std::convert::Infallible;
|
21
|
+
/// use rustfsm_trait::{StateMachine, TransitionResult};
|
22
|
+
///
|
23
|
+
/// fsm! {
|
24
|
+
/// name CardReader; command Commands; error Infallible; shared_state SharedState;
|
25
|
+
///
|
26
|
+
/// Locked --(CardReadable(CardData), shared on_card_readable) --> ReadingCard;
|
27
|
+
/// Locked --(CardReadable(CardData), shared on_card_readable) --> Locked;
|
28
|
+
/// ReadingCard --(CardAccepted, on_card_accepted) --> DoorOpen;
|
29
|
+
/// ReadingCard --(CardRejected, on_card_rejected) --> Locked;
|
30
|
+
/// DoorOpen --(DoorClosed, on_door_closed) --> Locked;
|
31
|
+
/// }
|
32
|
+
///
|
33
|
+
/// #[derive(Clone)]
|
34
|
+
/// pub struct SharedState {
|
35
|
+
/// last_id: Option<String>
|
36
|
+
/// }
|
37
|
+
///
|
38
|
+
/// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
39
|
+
/// pub enum Commands {
|
40
|
+
/// StartBlinkingLight,
|
41
|
+
/// StopBlinkingLight,
|
42
|
+
/// ProcessData(CardData),
|
43
|
+
/// }
|
44
|
+
///
|
45
|
+
/// type CardData = String;
|
46
|
+
///
|
47
|
+
/// /// Door is locked / idle / we are ready to read
|
48
|
+
/// #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
49
|
+
/// pub struct Locked {}
|
50
|
+
///
|
51
|
+
/// /// Actively reading the card
|
52
|
+
/// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
53
|
+
/// pub struct ReadingCard {
|
54
|
+
/// card_data: CardData,
|
55
|
+
/// }
|
56
|
+
///
|
57
|
+
/// /// The door is open, we shouldn't be accepting cards and should be blinking the light
|
58
|
+
/// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
59
|
+
/// pub struct DoorOpen {}
|
60
|
+
/// impl DoorOpen {
|
61
|
+
/// fn on_door_closed(&self) -> CardReaderTransition<Locked> {
|
62
|
+
/// TransitionResult::ok(vec![], Locked {})
|
63
|
+
/// }
|
64
|
+
/// }
|
65
|
+
///
|
66
|
+
/// impl Locked {
|
67
|
+
/// fn on_card_readable(&self, shared_dat: SharedState, data: CardData)
|
68
|
+
/// -> CardReaderTransition<ReadingCardOrLocked> {
|
69
|
+
/// match shared_dat.last_id {
|
70
|
+
/// // Arbitrarily deny the same person entering twice in a row
|
71
|
+
/// Some(d) if d == data => TransitionResult::ok(vec![], Locked {}.into()),
|
72
|
+
/// _ => {
|
73
|
+
/// // Otherwise issue a processing command. This illustrates using the same handler
|
74
|
+
/// // for different destinations
|
75
|
+
/// TransitionResult::ok_shared(
|
76
|
+
/// vec![
|
77
|
+
/// Commands::ProcessData(data.clone()),
|
78
|
+
/// Commands::StartBlinkingLight,
|
79
|
+
/// ],
|
80
|
+
/// ReadingCard { card_data: data.clone() }.into(),
|
81
|
+
/// SharedState { last_id: Some(data) }
|
82
|
+
/// )
|
83
|
+
/// }
|
84
|
+
/// }
|
85
|
+
/// }
|
86
|
+
/// }
|
87
|
+
///
|
88
|
+
/// impl ReadingCard {
|
89
|
+
/// fn on_card_accepted(&self) -> CardReaderTransition<DoorOpen> {
|
90
|
+
/// TransitionResult::ok(vec![Commands::StopBlinkingLight], DoorOpen {})
|
91
|
+
/// }
|
92
|
+
/// fn on_card_rejected(&self) -> CardReaderTransition<Locked> {
|
93
|
+
/// TransitionResult::ok(vec![Commands::StopBlinkingLight], Locked {})
|
94
|
+
/// }
|
95
|
+
/// }
|
96
|
+
///
|
97
|
+
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
98
|
+
/// let crs = CardReaderState::Locked(Locked {});
|
99
|
+
/// let mut cr = CardReader { state: crs, shared_state: SharedState { last_id: None } };
|
100
|
+
/// let cmds = cr.on_event_mut(CardReaderEvents::CardReadable("badguy".to_string()))?;
|
101
|
+
/// assert_eq!(cmds[0], Commands::ProcessData("badguy".to_string()));
|
102
|
+
/// assert_eq!(cmds[1], Commands::StartBlinkingLight);
|
103
|
+
///
|
104
|
+
/// let cmds = cr.on_event_mut(CardReaderEvents::CardRejected)?;
|
105
|
+
/// assert_eq!(cmds[0], Commands::StopBlinkingLight);
|
106
|
+
///
|
107
|
+
/// let cmds = cr.on_event_mut(CardReaderEvents::CardReadable("goodguy".to_string()))?;
|
108
|
+
/// assert_eq!(cmds[0], Commands::ProcessData("goodguy".to_string()));
|
109
|
+
/// assert_eq!(cmds[1], Commands::StartBlinkingLight);
|
110
|
+
///
|
111
|
+
/// let cmds = cr.on_event_mut(CardReaderEvents::CardAccepted)?;
|
112
|
+
/// assert_eq!(cmds[0], Commands::StopBlinkingLight);
|
113
|
+
/// # Ok(())
|
114
|
+
/// # }
|
115
|
+
/// ```
|
116
|
+
///
|
117
|
+
/// In the above example the first word is the name of the state machine, then after the comma the
|
118
|
+
/// type (which you must define separately) of commands produced by the machine.
|
119
|
+
///
|
120
|
+
/// then each line represents a transition, where the first word is the initial state, the tuple
|
121
|
+
/// inside the arrow is `(eventtype[, event handler])`, and the word after the arrow is the
|
122
|
+
/// destination state. here `eventtype` is an enum variant , and `event_handler` is a function you
|
123
|
+
/// must define outside the enum whose form depends on the event variant. the only variant types
|
124
|
+
/// allowed are unit and one-item tuple variants. For unit variants, the function takes no
|
125
|
+
/// parameters. For the tuple variants, the function takes the variant data as its parameter. In
|
126
|
+
/// either case the function is expected to return a `TransitionResult` to the appropriate state.
|
127
|
+
///
|
128
|
+
/// The first transition can be interpreted as "If the machine is in the locked state, when a
|
129
|
+
/// `CardReadable` event is seen, call `on_card_readable` (passing in `CardData`) and transition to
|
130
|
+
/// the `ReadingCard` state.
|
131
|
+
///
|
132
|
+
/// The macro will generate a few things:
|
133
|
+
/// * A struct for the overall state machine, named with the provided name. Here:
|
134
|
+
/// ```text
|
135
|
+
/// struct CardMachine {
|
136
|
+
/// state: CardMachineState,
|
137
|
+
/// shared_state: CardId,
|
138
|
+
/// }
|
139
|
+
/// ```
|
140
|
+
/// * An enum with a variant for each state, named with the provided name + "State".
|
141
|
+
/// ```text
|
142
|
+
/// enum CardMachineState {
|
143
|
+
/// Locked(Locked),
|
144
|
+
/// ReadingCard(ReadingCard),
|
145
|
+
/// Unlocked(Unlocked),
|
146
|
+
/// }
|
147
|
+
/// ```
|
148
|
+
///
|
149
|
+
/// You are expected to define a type for each state, to contain that state's data. If there is
|
150
|
+
/// no data, you can simply: `type StateName = ()`
|
151
|
+
/// * For any instance of transitions with the same event/handler which transition to different
|
152
|
+
/// destination states (dynamic destinations), an enum named like `DestAOrDestBOrDestC` is
|
153
|
+
/// generated. This enum must be used as the destination "state" from those handlers.
|
154
|
+
/// * An enum with a variant for each event. You are expected to define the type (if any) contained
|
155
|
+
/// in the event variant.
|
156
|
+
/// ```text
|
157
|
+
/// enum CardMachineEvents {
|
158
|
+
/// CardReadable(CardData)
|
159
|
+
/// }
|
160
|
+
/// ```
|
161
|
+
/// * An implementation of the [StateMachine](trait.StateMachine.html) trait for the generated state
|
162
|
+
/// machine enum (in this case, `CardMachine`)
|
163
|
+
/// * A type alias for a [TransitionResult](enum.TransitionResult.html) with the appropriate generic
|
164
|
+
/// parameters set for your machine. It is named as your machine with `Transition` appended. In
|
165
|
+
/// this case, `CardMachineTransition`.
|
166
|
+
#[proc_macro]
|
167
|
+
pub fn fsm(input: TokenStream) -> TokenStream {
|
168
|
+
let def: StateMachineDefinition = parse_macro_input!(input as StateMachineDefinition);
|
169
|
+
def.codegen()
|
170
|
+
}
|
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: Punctuated<Transition, Token![;]> =
|
213
|
+
input.parse_terminated(Transition::parse)?;
|
214
|
+
let transitions: Vec<_> = transitions.into_iter().collect();
|
215
|
+
// Check for and whine about any identical transitions. We do this here because preserving
|
216
|
+
// the order transitions were defined in is important, so simply collecting to a set is
|
217
|
+
// not ideal.
|
218
|
+
let trans_set: HashSet<_> = transitions.iter().collect();
|
219
|
+
if trans_set.len() != transitions.len() {
|
220
|
+
return Err(syn::Error::new(
|
221
|
+
input.span(),
|
222
|
+
"Duplicate transitions are not allowed!",
|
223
|
+
));
|
224
|
+
}
|
225
|
+
Ok(Self {
|
226
|
+
visibility,
|
227
|
+
name,
|
228
|
+
shared_state_type,
|
229
|
+
command_type,
|
230
|
+
error_type,
|
231
|
+
transitions,
|
232
|
+
})
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
fn parse_machine_types(input: ParseStream) -> Result<(Ident, Ident, Ident, Option<Type>)> {
|
237
|
+
let _: kw::name = input.parse()?;
|
238
|
+
let name: Ident = input.parse()?;
|
239
|
+
input.parse::<Token![;]>()?;
|
240
|
+
|
241
|
+
let _: kw::command = input.parse()?;
|
242
|
+
let command_type: Ident = input.parse()?;
|
243
|
+
input.parse::<Token![;]>()?;
|
244
|
+
|
245
|
+
let _: kw::error = input.parse()?;
|
246
|
+
let error_type: Ident = input.parse()?;
|
247
|
+
input.parse::<Token![;]>()?;
|
248
|
+
|
249
|
+
let shared_state_type: Option<Type> = if input.peek(kw::shared_state) {
|
250
|
+
let _: kw::shared_state = input.parse()?;
|
251
|
+
let typep = input.parse()?;
|
252
|
+
input.parse::<Token![;]>()?;
|
253
|
+
Some(typep)
|
254
|
+
} else {
|
255
|
+
None
|
256
|
+
};
|
257
|
+
Ok((name, command_type, error_type, shared_state_type))
|
258
|
+
}
|
259
|
+
|
260
|
+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
261
|
+
struct Transition {
|
262
|
+
from: Ident,
|
263
|
+
to: Vec<Ident>,
|
264
|
+
event: Variant,
|
265
|
+
handler: Option<Ident>,
|
266
|
+
mutates_shared: bool,
|
267
|
+
}
|
268
|
+
|
269
|
+
impl Parse for Transition {
|
270
|
+
fn parse(input: ParseStream) -> Result<Self> {
|
271
|
+
// Parse the initial state name
|
272
|
+
let from: Ident = input.parse()?;
|
273
|
+
// Parse at least one dash
|
274
|
+
input.parse::<Token![-]>()?;
|
275
|
+
while input.peek(Token![-]) {
|
276
|
+
input.parse::<Token![-]>()?;
|
277
|
+
}
|
278
|
+
// Parse transition information inside parens
|
279
|
+
let transition_info;
|
280
|
+
parenthesized!(transition_info in input);
|
281
|
+
// Get the event variant definition
|
282
|
+
let event: Variant = transition_info.parse()?;
|
283
|
+
// Reject non-unit or single-item-tuple variants
|
284
|
+
match &event.fields {
|
285
|
+
Fields::Named(_) => {
|
286
|
+
return Err(Error::new(
|
287
|
+
event.span(),
|
288
|
+
"Struct variants are not supported for events",
|
289
|
+
))
|
290
|
+
}
|
291
|
+
Fields::Unnamed(uf) => {
|
292
|
+
if uf.unnamed.len() != 1 {
|
293
|
+
return Err(Error::new(
|
294
|
+
event.span(),
|
295
|
+
"Only tuple variants with exactly one item are supported for events",
|
296
|
+
));
|
297
|
+
}
|
298
|
+
}
|
299
|
+
Fields::Unit => {}
|
300
|
+
}
|
301
|
+
// Check if there is an event handler, and parse it
|
302
|
+
let (mutates_shared, handler) = if transition_info.peek(Token![,]) {
|
303
|
+
transition_info.parse::<Token![,]>()?;
|
304
|
+
// Check for mut keyword signifying handler wants to mutate shared state
|
305
|
+
let mutates = if transition_info.peek(kw::shared) {
|
306
|
+
transition_info.parse::<kw::shared>()?;
|
307
|
+
true
|
308
|
+
} else {
|
309
|
+
false
|
310
|
+
};
|
311
|
+
(mutates, Some(transition_info.parse()?))
|
312
|
+
} else {
|
313
|
+
(false, None)
|
314
|
+
};
|
315
|
+
// Parse at least one dash followed by the "arrow"
|
316
|
+
input.parse::<Token![-]>()?;
|
317
|
+
while input.peek(Token![-]) {
|
318
|
+
input.parse::<Token![-]>()?;
|
319
|
+
}
|
320
|
+
input.parse::<Token![>]>()?;
|
321
|
+
// Parse the destination state
|
322
|
+
let to: Ident = input.parse()?;
|
323
|
+
|
324
|
+
Ok(Self {
|
325
|
+
from,
|
326
|
+
event,
|
327
|
+
handler,
|
328
|
+
to: vec![to],
|
329
|
+
mutates_shared,
|
330
|
+
})
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
impl StateMachineDefinition {
|
335
|
+
fn codegen(&self) -> TokenStream {
|
336
|
+
let visibility = self.visibility.clone();
|
337
|
+
// First extract all of the states into a set, and build the enum's insides
|
338
|
+
let states = self.all_states();
|
339
|
+
let state_variants = states.iter().map(|s| {
|
340
|
+
let statestr = s.to_string();
|
341
|
+
quote! {
|
342
|
+
#[display(fmt=#statestr)]
|
343
|
+
#s(#s)
|
344
|
+
}
|
345
|
+
});
|
346
|
+
let name = &self.name;
|
347
|
+
let name_str = &self.name.to_string();
|
348
|
+
|
349
|
+
let transition_result_name = Ident::new(&format!("{}Transition", name), name.span());
|
350
|
+
let transition_type_alias = quote! {
|
351
|
+
type #transition_result_name<Ds, Sm = #name> = TransitionResult<Sm, Ds>;
|
352
|
+
};
|
353
|
+
|
354
|
+
let state_enum_name = Ident::new(&format!("{}State", name), name.span());
|
355
|
+
// If user has not defined any shared state, use the unit type.
|
356
|
+
let shared_state_type = self
|
357
|
+
.shared_state_type
|
358
|
+
.clone()
|
359
|
+
.unwrap_or_else(|| syn::parse_str("()").unwrap());
|
360
|
+
let machine_struct = quote! {
|
361
|
+
#[derive(Clone)]
|
362
|
+
#visibility struct #name {
|
363
|
+
state: #state_enum_name,
|
364
|
+
shared_state: #shared_state_type
|
365
|
+
}
|
366
|
+
};
|
367
|
+
let states_enum = quote! {
|
368
|
+
#[derive(::derive_more::From, Clone, ::derive_more::Display)]
|
369
|
+
#visibility enum #state_enum_name {
|
370
|
+
#(#state_variants),*
|
371
|
+
}
|
372
|
+
};
|
373
|
+
let state_is_final_match_arms = states.iter().map(|s| {
|
374
|
+
let val = if self.is_final_state(s) {
|
375
|
+
quote! { true }
|
376
|
+
} else {
|
377
|
+
quote! { false }
|
378
|
+
};
|
379
|
+
quote! { #state_enum_name::#s(_) => #val }
|
380
|
+
});
|
381
|
+
let states_enum_impl = quote! {
|
382
|
+
impl #state_enum_name {
|
383
|
+
fn is_final(&self) -> bool {
|
384
|
+
match self {
|
385
|
+
#(#state_is_final_match_arms),*
|
386
|
+
}
|
387
|
+
}
|
388
|
+
}
|
389
|
+
};
|
390
|
+
|
391
|
+
// Build the events enum
|
392
|
+
let events: HashSet<Variant> = self.transitions.iter().map(|t| t.event.clone()).collect();
|
393
|
+
let events_enum_name = Ident::new(&format!("{}Events", name), name.span());
|
394
|
+
let events: Vec<_> = events
|
395
|
+
.into_iter()
|
396
|
+
.map(|v| {
|
397
|
+
let vname = v.ident.to_string();
|
398
|
+
quote! {
|
399
|
+
#[display(fmt=#vname)]
|
400
|
+
#v
|
401
|
+
}
|
402
|
+
})
|
403
|
+
.collect();
|
404
|
+
let events_enum = quote! {
|
405
|
+
#[derive(::derive_more::Display)]
|
406
|
+
#visibility enum #events_enum_name {
|
407
|
+
#(#events),*
|
408
|
+
}
|
409
|
+
};
|
410
|
+
|
411
|
+
// Construct the trait implementation
|
412
|
+
let cmd_type = &self.command_type;
|
413
|
+
let err_type = &self.error_type;
|
414
|
+
let mut statemap: HashMap<Ident, Vec<Transition>> = HashMap::new();
|
415
|
+
for t in &self.transitions {
|
416
|
+
statemap
|
417
|
+
.entry(t.from.clone())
|
418
|
+
.and_modify(|v| v.push(t.clone()))
|
419
|
+
.or_insert_with(|| vec![t.clone()]);
|
420
|
+
}
|
421
|
+
// Add any states without any transitions to the map
|
422
|
+
for s in &states {
|
423
|
+
if !statemap.contains_key(s) {
|
424
|
+
statemap.insert(s.clone(), vec![]);
|
425
|
+
}
|
426
|
+
}
|
427
|
+
let mut multi_dest_enums = vec![];
|
428
|
+
let state_branches: Vec<_> = statemap.into_iter().map(|(from, transitions)| {
|
429
|
+
// Merge transition dest states with the same handler
|
430
|
+
let transitions = merge_transition_dests(transitions);
|
431
|
+
let event_branches = transitions
|
432
|
+
.into_iter()
|
433
|
+
.map(|ts| {
|
434
|
+
let ev_variant = &ts.event.ident;
|
435
|
+
if let Some(ts_fn) = ts.handler.clone() {
|
436
|
+
let span = ts_fn.span();
|
437
|
+
let trans_type = match ts.to.as_slice() {
|
438
|
+
[] => unreachable!("There will be at least one dest state in transitions"),
|
439
|
+
[one_to] => quote! {
|
440
|
+
#transition_result_name<#one_to>
|
441
|
+
},
|
442
|
+
multi_dests => {
|
443
|
+
let string_dests: Vec<_> = multi_dests.iter()
|
444
|
+
.map(ToString::to_string).collect();
|
445
|
+
let enum_ident = Ident::new(&string_dests.join("Or"),
|
446
|
+
multi_dests[0].span());
|
447
|
+
let multi_dest_enum = quote! {
|
448
|
+
#[derive(::derive_more::From)]
|
449
|
+
#visibility enum #enum_ident {
|
450
|
+
#(#multi_dests(#multi_dests)),*
|
451
|
+
}
|
452
|
+
impl ::core::convert::From<#enum_ident> for #state_enum_name {
|
453
|
+
fn from(v: #enum_ident) -> Self {
|
454
|
+
match v {
|
455
|
+
#( #enum_ident::#multi_dests(sv) =>
|
456
|
+
Self::#multi_dests(sv) ),*
|
457
|
+
}
|
458
|
+
}
|
459
|
+
}
|
460
|
+
};
|
461
|
+
multi_dest_enums.push(multi_dest_enum);
|
462
|
+
quote! {
|
463
|
+
#transition_result_name<#enum_ident>
|
464
|
+
}
|
465
|
+
}
|
466
|
+
};
|
467
|
+
match ts.event.fields {
|
468
|
+
Fields::Unnamed(_) => {
|
469
|
+
let arglist = if ts.mutates_shared {
|
470
|
+
quote! {self.shared_state, val}
|
471
|
+
} else {
|
472
|
+
quote! {val}
|
473
|
+
};
|
474
|
+
quote_spanned! {span=>
|
475
|
+
#events_enum_name::#ev_variant(val) => {
|
476
|
+
let res: #trans_type = state_data.#ts_fn(#arglist);
|
477
|
+
res.into_general()
|
478
|
+
}
|
479
|
+
}
|
480
|
+
}
|
481
|
+
Fields::Unit => {
|
482
|
+
let arglist = if ts.mutates_shared {
|
483
|
+
quote! {self.shared_state}
|
484
|
+
} else {
|
485
|
+
quote! {}
|
486
|
+
};
|
487
|
+
quote_spanned! {span=>
|
488
|
+
#events_enum_name::#ev_variant => {
|
489
|
+
let res: #trans_type = state_data.#ts_fn(#arglist);
|
490
|
+
res.into_general()
|
491
|
+
}
|
492
|
+
}
|
493
|
+
}
|
494
|
+
Fields::Named(_) => unreachable!(),
|
495
|
+
}
|
496
|
+
} else {
|
497
|
+
// If events do not have a handler, attempt to construct the next state
|
498
|
+
// using `Default`.
|
499
|
+
if let [new_state] = ts.to.as_slice() {
|
500
|
+
let span = new_state.span();
|
501
|
+
let default_trans = quote_spanned! {span=>
|
502
|
+
TransitionResult::<_, #new_state>::from::<#from>(state_data).into_general()
|
503
|
+
};
|
504
|
+
let span = ts.event.span();
|
505
|
+
match ts.event.fields {
|
506
|
+
Fields::Unnamed(_) => quote_spanned! {span=>
|
507
|
+
#events_enum_name::#ev_variant(_val) => {
|
508
|
+
#default_trans
|
509
|
+
}
|
510
|
+
},
|
511
|
+
Fields::Unit => quote_spanned! {span=>
|
512
|
+
#events_enum_name::#ev_variant => {
|
513
|
+
#default_trans
|
514
|
+
}
|
515
|
+
},
|
516
|
+
Fields::Named(_) => unreachable!(),
|
517
|
+
}
|
518
|
+
|
519
|
+
} else {
|
520
|
+
unreachable!("It should be impossible to have more than one dest state in no-handler transitions")
|
521
|
+
}
|
522
|
+
}
|
523
|
+
})
|
524
|
+
// Since most states won't handle every possible event, return an error to that effect
|
525
|
+
.chain(std::iter::once(
|
526
|
+
quote! { _ => { return TransitionResult::InvalidTransition } },
|
527
|
+
));
|
528
|
+
quote! {
|
529
|
+
#state_enum_name::#from(state_data) => match event {
|
530
|
+
#(#event_branches),*
|
531
|
+
}
|
532
|
+
}
|
533
|
+
}).collect();
|
534
|
+
|
535
|
+
let viz_str = self.visualize();
|
536
|
+
|
537
|
+
let trait_impl = quote! {
|
538
|
+
impl ::rustfsm::StateMachine for #name {
|
539
|
+
type Error = #err_type;
|
540
|
+
type State = #state_enum_name;
|
541
|
+
type SharedState = #shared_state_type;
|
542
|
+
type Event = #events_enum_name;
|
543
|
+
type Command = #cmd_type;
|
544
|
+
|
545
|
+
fn name(&self) -> &str {
|
546
|
+
#name_str
|
547
|
+
}
|
548
|
+
|
549
|
+
fn on_event(self, event: #events_enum_name)
|
550
|
+
-> ::rustfsm::TransitionResult<Self, Self::State> {
|
551
|
+
match self.state {
|
552
|
+
#(#state_branches),*
|
553
|
+
}
|
554
|
+
}
|
555
|
+
|
556
|
+
fn state(&self) -> &Self::State {
|
557
|
+
&self.state
|
558
|
+
}
|
559
|
+
|
560
|
+
fn set_state(&mut self, new: Self::State) {
|
561
|
+
self.state = new
|
562
|
+
}
|
563
|
+
|
564
|
+
fn shared_state(&self) -> &Self::SharedState{
|
565
|
+
&self.shared_state
|
566
|
+
}
|
567
|
+
|
568
|
+
fn has_reached_final_state(&self) -> bool {
|
569
|
+
self.state.is_final()
|
570
|
+
}
|
571
|
+
|
572
|
+
fn from_parts(shared: Self::SharedState, state: Self::State) -> Self {
|
573
|
+
Self { shared_state: shared, state }
|
574
|
+
}
|
575
|
+
|
576
|
+
fn visualizer() -> &'static str {
|
577
|
+
#viz_str
|
578
|
+
}
|
579
|
+
}
|
580
|
+
};
|
581
|
+
|
582
|
+
let output = quote! {
|
583
|
+
#transition_type_alias
|
584
|
+
#machine_struct
|
585
|
+
#states_enum
|
586
|
+
#(#multi_dest_enums)*
|
587
|
+
#states_enum_impl
|
588
|
+
#events_enum
|
589
|
+
#trait_impl
|
590
|
+
};
|
591
|
+
|
592
|
+
TokenStream::from(output)
|
593
|
+
}
|
594
|
+
|
595
|
+
fn all_states(&self) -> HashSet<Ident> {
|
596
|
+
self.transitions
|
597
|
+
.iter()
|
598
|
+
.flat_map(|t| {
|
599
|
+
let mut states = t.to.clone();
|
600
|
+
states.push(t.from.clone());
|
601
|
+
states
|
602
|
+
})
|
603
|
+
.collect()
|
604
|
+
}
|
605
|
+
|
606
|
+
fn visualize(&self) -> String {
|
607
|
+
let transitions: Vec<String> = self
|
608
|
+
.transitions
|
609
|
+
.iter()
|
610
|
+
.flat_map(|t| {
|
611
|
+
t.to.iter()
|
612
|
+
.map(move |d| format!("{} --> {}: {}", t.from, d, t.event.ident))
|
613
|
+
})
|
614
|
+
// Add all final state transitions
|
615
|
+
.chain(
|
616
|
+
self.all_states()
|
617
|
+
.iter()
|
618
|
+
.filter(|s| self.is_final_state(s))
|
619
|
+
.map(|s| format!("{} --> [*]", s)),
|
620
|
+
)
|
621
|
+
.collect();
|
622
|
+
let transitions = transitions.join("\n");
|
623
|
+
format!("@startuml\n{}\n@enduml", transitions)
|
624
|
+
}
|
625
|
+
}
|
626
|
+
|
627
|
+
/// Merge transition's dest state lists for those with the same from state & handler
|
628
|
+
fn merge_transition_dests(transitions: Vec<Transition>) -> Vec<Transition> {
|
629
|
+
let mut map = HashMap::<_, Transition>::new();
|
630
|
+
for t in transitions {
|
631
|
+
// We want to use the transition sans-destinations as the key
|
632
|
+
let without_dests = {
|
633
|
+
let mut wd = t.clone();
|
634
|
+
wd.to = vec![];
|
635
|
+
wd
|
636
|
+
};
|
637
|
+
match map.entry(without_dests) {
|
638
|
+
Entry::Occupied(mut e) => {
|
639
|
+
e.get_mut().to.extend(t.to.into_iter());
|
640
|
+
}
|
641
|
+
Entry::Vacant(v) => {
|
642
|
+
v.insert(t);
|
643
|
+
}
|
644
|
+
}
|
645
|
+
}
|
646
|
+
map.into_iter().map(|(_, v)| v).collect()
|
647
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
extern crate rustfsm_trait as rustfsm;
|
2
|
+
|
3
|
+
use rustfsm_procmacro::fsm;
|
4
|
+
|
5
|
+
fsm! {
|
6
|
+
name SimpleMachine; command SimpleMachineCommand; error Infallible;
|
7
|
+
|
8
|
+
One --(A)--> Two;
|
9
|
+
One --(A)--> Two;
|
10
|
+
}
|
11
|
+
|
12
|
+
#[derive(Default, Clone)]
|
13
|
+
pub struct One {}
|
14
|
+
|
15
|
+
#[derive(Default, Clone)]
|
16
|
+
pub struct Two {}
|
17
|
+
|
18
|
+
fn main() {}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
error: Duplicate transitions are not allowed!
|
2
|
+
--> $DIR/dupe_transitions_fail.rs:5:1
|
3
|
+
|
|
4
|
+
5 | / fsm! {
|
5
|
+
6 | | name SimpleMachine; command SimpleMachineCommand; error Infallible;
|
6
|
+
7 | |
|
7
|
+
8 | | One --(A)--> Two;
|
8
|
+
9 | | One --(A)--> Two;
|
9
|
+
10 | | }
|
10
|
+
| |_^
|
11
|
+
|
|
12
|
+
= note: this error originates in the macro `fsm` (in Nightly builds, run with -Z macro-backtrace for more info)
|