#pragma once #include "fesa/core/diagnostic.hpp" #include #include #include #include namespace fesa { // Maps a failure to the stable command-line exit-code classes defined by V0. enum class FailureCategory { input, model, solver, output }; // Transports success or structured diagnostics without exposing backend errors. class Status { public: static Status ok(); static Status failure(std::vector diagnostics); static Status failure( FailureCategory category, std::vector diagnostics); bool isOk() const noexcept; std::optional failureCategory() const noexcept; const std::vector& diagnostics() const noexcept; private: Status( bool isOk, std::optional category, std::vector diagnostics); bool isOk_; std::optional category_; std::vector diagnostics_; }; // Owns exactly one successful value or one failed Status. template class Result { public: static Result success(T value) { return Result{SuccessTag{}, std::move(value)}; } static Result failure(Status status) { if (status.isOk()) { throw std::invalid_argument{"A failed Result requires a failed Status."}; } return Result{FailureTag{}, std::move(status)}; } bool hasValue() const noexcept { return value_.has_value(); } T& value() { if (!value_) { throw std::logic_error{"Result has no value."}; } return *value_; } const T& value() const { if (!value_) { throw std::logic_error{"Result has no value."}; } return *value_; } const Status& status() const noexcept { return status_; } private: struct SuccessTag {}; struct FailureTag {}; Result(SuccessTag, T value) : value_{std::move(value)}, status_{Status::ok()} {} Result(FailureTag, Status status) : value_{std::nullopt}, status_{std::move(status)} {} std::optional value_; Status status_; }; } // namespace fesa