From 42c439c019b27656d588d3f2863bbea021c338ee Mon Sep 17 00:00:00 2001 From: koparasy Date: Wed, 17 Dec 2025 13:12:17 -0800 Subject: [PATCH 1/6] Adding actions --- src/AMSlib/wf/action.hpp | 26 ++++++++++++++++++ tests/AMSlib/wf/CMakeLists.txt | 3 ++ tests/AMSlib/wf/action.cpp | 50 ++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/AMSlib/wf/action.hpp create mode 100644 tests/AMSlib/wf/action.cpp diff --git a/src/AMSlib/wf/action.hpp b/src/AMSlib/wf/action.hpp new file mode 100644 index 00000000..64035c7c --- /dev/null +++ b/src/AMSlib/wf/action.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace ams +{ + +struct EvalContext; // forward declaration + +/// Base class for a single step in an AMS evaluation pipeline. +/// +/// Actions mutate the shared EvalContext and may fail; failures are reported +/// via AMSStatus so pipelines can short-circuit cleanly. +class Action +{ +public: + virtual ~Action() = default; + + /// Execute this action on the evaluation context. + virtual AMSStatus run(EvalContext& ctx) = 0; + + /// Human-readable name for debugging, logging, and tracing. + virtual const char* name() const noexcept = 0; +}; + +} // namespace ams diff --git a/tests/AMSlib/wf/CMakeLists.txt b/tests/AMSlib/wf/CMakeLists.txt index 018b04b2..594bdd55 100644 --- a/tests/AMSlib/wf/CMakeLists.txt +++ b/tests/AMSlib/wf/CMakeLists.txt @@ -56,3 +56,6 @@ ADD_WORKFLOW_UNIT_TEST(WORKFLOW::EVAL_CONTEXT eval_context) BUILD_UNIT_TEST(pointwise pointwise_layout_transform.cpp) ADD_WORKFLOW_UNIT_TEST(WORKFLOW::POINTWISE pointwise) + +BUILD_UNIT_TEST(action action.cpp) +ADD_WORKFLOW_UNIT_TEST(WORKFLOW::ACTION action) diff --git a/tests/AMSlib/wf/action.cpp b/tests/AMSlib/wf/action.cpp new file mode 100644 index 00000000..746cc18a --- /dev/null +++ b/tests/AMSlib/wf/action.cpp @@ -0,0 +1,50 @@ +#include "wf/action.hpp" + +#include +#include +#include + +// Prefer the real EvalContext if available. +// If your project uses a different header name, adjust accordingly. +#include "wf/eval_context.hpp" + +namespace ams +{ + +namespace +{ +class TestAction final : public Action +{ +public: + const char* name() const noexcept override { return "TestAction"; } + + AMSStatus run(EvalContext& ctx) override + { + ctx.Threshold = ctx.Threshold.value_or(0.0f) + 1.0f; + return {}; + } +}; +} // namespace + +CATCH_TEST_CASE("Action: abstract base class + virtual interface", + "[wf][action]") +{ + CATCH_STATIC_REQUIRE(std::is_abstract_v); + CATCH_STATIC_REQUIRE(std::has_virtual_destructor_v); + + EvalContext ctx{}; + ctx.Threshold = 0.0f; + std::unique_ptr act = std::make_unique(); + + CATCH_REQUIRE(act->name() == std::string("TestAction")); + + auto Err = act->run(ctx); + CATCH_REQUIRE(Err); + CATCH_REQUIRE(ctx.Threshold == 1.0f); + + auto Err1 = act->run(ctx); + CATCH_REQUIRE(Err1); + CATCH_REQUIRE(ctx.Threshold == 2.0f); +} + +} // namespace ams From d2ba2d974ae4c353f76bc2facdd3f69c6d889348 Mon Sep 17 00:00:00 2001 From: koparasy Date: Wed, 17 Dec 2025 13:28:56 -0800 Subject: [PATCH 2/6] Add pipeline, a sequence of actions --- src/AMSlib/wf/pipeline.hpp | 55 ++++++++++++++++++++++ tests/AMSlib/wf/CMakeLists.txt | 3 ++ tests/AMSlib/wf/pipeline.cpp | 86 ++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 src/AMSlib/wf/pipeline.hpp create mode 100644 tests/AMSlib/wf/pipeline.cpp diff --git a/src/AMSlib/wf/pipeline.hpp b/src/AMSlib/wf/pipeline.hpp new file mode 100644 index 00000000..bcdeb68a --- /dev/null +++ b/src/AMSlib/wf/pipeline.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include "AMSError.hpp" // AMSStatus +#include "wf/action.hpp" // Action + +namespace ams +{ + +struct EvalContext; + +/// A linear sequence of Actions executed in order. +/// +/// If any Action fails, execution stops and the error is returned. +class Pipeline +{ +public: + using ActionPtr = std::unique_ptr; + + Pipeline() = default; + + /// Append an Action to the pipeline. + Pipeline& add(ActionPtr Act) + { + Actions.emplace_back(std::move(Act)); + return *this; + } + + /// Execute all actions in order; stops on first error. + AMSStatus run(EvalContext& Ctx) + { + for (auto& Act : Actions) { + if (auto St = Act->run(Ctx); !St) { + return St; + } + } + return {}; + } + + /// Number of actions in the pipeline. + size_t size() const noexcept { return Actions.size(); } + + /// True if there are no actions. + bool empty() const noexcept { return Actions.empty(); } + + /// Remove all actions. + void clear() noexcept { Actions.clear(); } + +private: + std::vector Actions; +}; + +} // namespace ams diff --git a/tests/AMSlib/wf/CMakeLists.txt b/tests/AMSlib/wf/CMakeLists.txt index 594bdd55..2c825b3c 100644 --- a/tests/AMSlib/wf/CMakeLists.txt +++ b/tests/AMSlib/wf/CMakeLists.txt @@ -59,3 +59,6 @@ ADD_WORKFLOW_UNIT_TEST(WORKFLOW::POINTWISE pointwise) BUILD_UNIT_TEST(action action.cpp) ADD_WORKFLOW_UNIT_TEST(WORKFLOW::ACTION action) + +BUILD_UNIT_TEST(pipeline pipeline.cpp) +ADD_WORKFLOW_UNIT_TEST(WORKFLOW::PIPELINE pipeline) diff --git a/tests/AMSlib/wf/pipeline.cpp b/tests/AMSlib/wf/pipeline.cpp new file mode 100644 index 00000000..2ec8e23e --- /dev/null +++ b/tests/AMSlib/wf/pipeline.cpp @@ -0,0 +1,86 @@ +#include "wf/pipeline.hpp" + +#include +#include +#include + +// Prefer the real EvalContext if available. +// If your project uses a different header name, adjust accordingly. +#if __has_include("wf/eval_context.hpp") +#include "wf/eval_context.hpp" +#else +namespace ams +{ +struct EvalContext { + int counter = 0; +}; +} // namespace ams +#endif + +namespace ams +{ + +namespace +{ + +class IncAction final : public Action +{ +public: + const char* name() const noexcept override { return "IncAction"; } + + AMSStatus run(EvalContext& ctx) override + { + ctx.Threshold = ctx.Threshold.value_or(0.0f) + 1.0f; + return {}; + } +}; + +class FailAction final : public Action +{ +public: + const char* name() const noexcept override { return "FailAction"; } + + AMSStatus run(EvalContext&) override + { + return AMS_MAKE_ERROR(AMSErrorType::Generic, "FailAction triggered"); + } +}; + +} // namespace + +CATCH_TEST_CASE("Pipeline runs actions in order and short-circuits on error", + "[wf][pipeline]") +{ + EvalContext Ctx{}; + Pipeline P; + + // Two increments -> counter becomes 2, then FailAction stops the pipeline. + P.add(std::make_unique()) + .add(std::make_unique()) + .add(std::make_unique()) + .add(std::make_unique()); // must NOT execute + + Ctx.Threshold = 0.0f; + + auto St = P.run(Ctx); + CATCH_REQUIRE_FALSE(St); + CATCH_REQUIRE(St.error().getType() == AMSErrorType::Generic); + + // Only the first two IncAction should have run. + CATCH_REQUIRE(Ctx.Threshold.value() == 2.0f); +} + +CATCH_TEST_CASE("Pipeline succeeds when all actions succeed", "[wf][pipeline]") +{ + EvalContext Ctx{}; + Pipeline P; + + P.add(std::make_unique()).add(std::make_unique()); + + Ctx.Threshold = 0.0f; + auto St = P.run(Ctx); + CATCH_REQUIRE(St); + CATCH_REQUIRE(Ctx.Threshold.value() == 2.0f); +} + +} // namespace ams From 36a4c52822a19b38d6772cba32cbbf749fbc215e Mon Sep 17 00:00:00 2001 From: Konstantinos Parasyris Date: Wed, 17 Dec 2025 15:38:50 -0800 Subject: [PATCH 3/6] Update tests/AMSlib/wf/pipeline.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/AMSlib/wf/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/AMSlib/wf/pipeline.cpp b/tests/AMSlib/wf/pipeline.cpp index 2ec8e23e..0b1fd1ab 100644 --- a/tests/AMSlib/wf/pipeline.cpp +++ b/tests/AMSlib/wf/pipeline.cpp @@ -54,7 +54,7 @@ CATCH_TEST_CASE("Pipeline runs actions in order and short-circuits on error", EvalContext Ctx{}; Pipeline P; - // Two increments -> counter becomes 2, then FailAction stops the pipeline. + // Two increments -> Threshold becomes 2, then FailAction stops the pipeline. P.add(std::make_unique()) .add(std::make_unique()) .add(std::make_unique()) From 658e70afbf92801295872ff17ea9be16ecb694f1 Mon Sep 17 00:00:00 2001 From: Konstantinos Parasyris Date: Wed, 17 Dec 2025 15:39:07 -0800 Subject: [PATCH 4/6] Update tests/AMSlib/wf/pipeline.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/AMSlib/wf/pipeline.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/AMSlib/wf/pipeline.cpp b/tests/AMSlib/wf/pipeline.cpp index 0b1fd1ab..c02bf26c 100644 --- a/tests/AMSlib/wf/pipeline.cpp +++ b/tests/AMSlib/wf/pipeline.cpp @@ -4,18 +4,7 @@ #include #include -// Prefer the real EvalContext if available. -// If your project uses a different header name, adjust accordingly. -#if __has_include("wf/eval_context.hpp") #include "wf/eval_context.hpp" -#else -namespace ams -{ -struct EvalContext { - int counter = 0; -}; -} // namespace ams -#endif namespace ams { From 32cb9412c0e416cd0d49ed36b54e18ee00f39ed7 Mon Sep 17 00:00:00 2001 From: Konstantinos Parasyris Date: Wed, 17 Dec 2025 15:39:19 -0800 Subject: [PATCH 5/6] Update src/AMSlib/wf/action.hpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/AMSlib/wf/action.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AMSlib/wf/action.hpp b/src/AMSlib/wf/action.hpp index 64035c7c..6f875119 100644 --- a/src/AMSlib/wf/action.hpp +++ b/src/AMSlib/wf/action.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include "AMSError.hpp" namespace ams { From 606f8f77b59644e9a4c843963b8ff0905a3964ec Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 16:02:08 -0800 Subject: [PATCH 6/6] Make Pipeline::run() const (#181) --- src/AMSlib/wf/pipeline.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AMSlib/wf/pipeline.hpp b/src/AMSlib/wf/pipeline.hpp index bcdeb68a..e412f0f0 100644 --- a/src/AMSlib/wf/pipeline.hpp +++ b/src/AMSlib/wf/pipeline.hpp @@ -29,9 +29,9 @@ class Pipeline } /// Execute all actions in order; stops on first error. - AMSStatus run(EvalContext& Ctx) + AMSStatus run(EvalContext& Ctx) const { - for (auto& Act : Actions) { + for (const auto& Act : Actions) { if (auto St = Act->run(Ctx); !St) { return St; }