diff options
author | rtk0c <[email protected]> | 2021-04-26 14:07:28 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-04-26 14:07:28 -0700 |
commit | b7d5b514e7bffd3149a99bc7f1424f8251876d85 (patch) | |
tree | 42f2867875c0b367fab2a6db7be395f8c777eb41 /core/src/Model | |
parent | e7afe82857ac3ccc3e10b40cee60ea94cc59232b (diff) |
Serialization for workflow stuff
Diffstat (limited to 'core/src/Model')
-rw-r--r-- | core/src/Model/Workflow/Evaluation.cpp | 34 | ||||
-rw-r--r-- | core/src/Model/Workflow/Evaluation.hpp | 6 | ||||
-rw-r--r-- | core/src/Model/Workflow/Value.cpp | 9 | ||||
-rw-r--r-- | core/src/Model/Workflow/Value.hpp | 17 | ||||
-rw-r--r-- | core/src/Model/Workflow/Value_Main.cpp | 19 | ||||
-rw-r--r-- | core/src/Model/Workflow/Value_RTTI.cpp | 22 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow.hpp | 40 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow_Main.cpp (renamed from core/src/Model/Workflow/Workflow.cpp) | 206 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow_RTTI.cpp | 51 |
9 files changed, 385 insertions, 19 deletions
diff --git a/core/src/Model/Workflow/Evaluation.cpp b/core/src/Model/Workflow/Evaluation.cpp index db09973..ff3edf4 100644 --- a/core/src/Model/Workflow/Evaluation.cpp +++ b/core/src/Model/Workflow/Evaluation.cpp @@ -2,6 +2,40 @@ #include <queue> +const char* WorkflowEvaluationError::FormatMessageType(enum MessageType messageType) { + switch (messageType) { + case Error: return "Error"; + case Warning: return "Warning"; + } +} + +const char* WorkflowEvaluationError::FormatPinType(enum PinType pinType) { + switch (pinType) { + case NoPin: return nullptr; + case InputPin: return "Input pin"; + case OutputPin: return "Output pin"; + } +} + +std::string WorkflowEvaluationError::Format() const { + // TODO convert to std::format + + std::string result; + result += FormatMessageType(this->Type); + result += " at "; + result += NodeId; + if (auto pinText = FormatPinType(this->PinType)) { + result += "/"; + result += pinText; + result += " "; + result += PinId; + } + result += ": "; + result += this->Message; + + return result; +} + namespace { enum class EvaluationStatus { Unevaluated, diff --git a/core/src/Model/Workflow/Evaluation.hpp b/core/src/Model/Workflow/Evaluation.hpp index be2e862..d068c45 100644 --- a/core/src/Model/Workflow/Evaluation.hpp +++ b/core/src/Model/Workflow/Evaluation.hpp @@ -26,6 +26,12 @@ public: int PinId; PinType PinType; MessageType Type; + +public: + static const char* FormatMessageType(enum MessageType messageType); + static const char* FormatPinType(enum PinType pinType); + + std::string Format() const; }; class WorkflowEvaluationContext { diff --git a/core/src/Model/Workflow/Value.cpp b/core/src/Model/Workflow/Value.cpp deleted file mode 100644 index 7e5aabf..0000000 --- a/core/src/Model/Workflow/Value.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Value.hpp" - -BaseValue::BaseValue(Kind kind) - : mKind{ kind } { -} - -BaseValue::Kind BaseValue::GetKind() const { - return mKind; -} diff --git a/core/src/Model/Workflow/Value.hpp b/core/src/Model/Workflow/Value.hpp index eb99c14..2748e16 100644 --- a/core/src/Model/Workflow/Value.hpp +++ b/core/src/Model/Workflow/Value.hpp @@ -1,5 +1,8 @@ #pragma once +#include <iosfwd> +#include <memory> + class BaseValue { public: enum Kind { @@ -8,14 +11,17 @@ public: KD_DateTime, /// An unspecified type, otherwise known as "any" in some contexts. - KindInvalid, - KindCount = KindInvalid, + InvalidKind, + KindCount = InvalidKind, }; private: Kind mKind; public: + static const char* FormatKind(Kind kind); + static std::unique_ptr<BaseValue> CreateByKind(Kind kind); + BaseValue(Kind kind); virtual ~BaseValue() = default; @@ -25,4 +31,11 @@ public: BaseValue& operator=(BaseValue&&) = default; Kind GetKind() const; + + // TODO get constant editor + + /// The functions \c ReadFrom, \c WriteTo will only be valid to call if this function returns true. + virtual bool SupportsConstant() const; + virtual void ReadFrom(std::istream& stream); + virtual void WriteTo(std::ostream& stream); }; diff --git a/core/src/Model/Workflow/Value_Main.cpp b/core/src/Model/Workflow/Value_Main.cpp new file mode 100644 index 0000000..2e64987 --- /dev/null +++ b/core/src/Model/Workflow/Value_Main.cpp @@ -0,0 +1,19 @@ +#include "Value.hpp" + +BaseValue::BaseValue(Kind kind) + : mKind{ kind } { +} + +BaseValue::Kind BaseValue::GetKind() const { + return mKind; +} + +bool BaseValue::SupportsConstant() const { + return false; +} + +void BaseValue::ReadFrom(std::istream& stream) { +} + +void BaseValue::WriteTo(std::ostream& stream) { +} diff --git a/core/src/Model/Workflow/Value_RTTI.cpp b/core/src/Model/Workflow/Value_RTTI.cpp new file mode 100644 index 0000000..f2c8f92 --- /dev/null +++ b/core/src/Model/Workflow/Value_RTTI.cpp @@ -0,0 +1,22 @@ +#include "Value.hpp" + +#include "Model/Workflow/Values/BasicValues.hpp" +#include "Utils/Macros.hpp" + +const char* BaseValue::FormatKind(Kind kind) { + switch (kind) { + case KD_Numeric: return "Numeric"; + case KD_Text: return "Text"; + case KD_DateTime: return "Date/time"; + case InvalidKind: UNREACHABLE; + } +} + +std::unique_ptr<BaseValue> BaseValue::CreateByKind(BaseValue::Kind kind) { + switch (kind) { + case KD_Numeric: return std::make_unique<NumericValue>(); + case KD_Text: return std::make_unique<TextValue>(); + case KD_DateTime: return std::make_unique<DateTimeValue>(); + case InvalidKind: return nullptr; + } +} diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp index 9c02168..db341af 100644 --- a/core/src/Model/Workflow/Workflow.hpp +++ b/core/src/Model/Workflow/Workflow.hpp @@ -6,6 +6,7 @@ #include <cstddef> #include <cstdint> +#include <iosfwd> #include <limits> #include <memory> #include <span> @@ -41,6 +42,10 @@ public: std::span<const ConnectionPoint> GetSourcePoints() const; std::span<ConnectionPoint> GetDestinationPoints(); std::span<const ConnectionPoint> GetDestinationPoints() const; + + void DrawDebugInfo() const; + void ReadFrom(std::istream& stream); + void WriteTo(std::ostream& stream); }; class WorkflowNode { @@ -71,7 +76,7 @@ public: protected: struct InputPin { size_t Connection = WorkflowConnection::kInvalidId; - BaseValue::Kind MatchingType = BaseValue::KindInvalid; + BaseValue::Kind MatchingType = BaseValue::InvalidKind; bool ConnectionToConst = false; bool AllowsMultipleConnections = false; @@ -84,7 +89,7 @@ protected: struct OutputPin { size_t Connection = WorkflowConnection::kInvalidId; - BaseValue::Kind MatchingType = BaseValue::KindInvalid; + BaseValue::Kind MatchingType = BaseValue::InvalidKind; bool AllowsMultipleConnections = false; bool IsConnected() const; @@ -100,11 +105,14 @@ protected: std::vector<InputPin> mInputs; std::vector<OutputPin> mOutputs; Vec2i mPosition; - Type mType; Kind mKind; int mDepth; public: + static const char* FormatKind(Kind kind); + static const char* FormatType(Type type); + static std::unique_ptr<WorkflowNode> CreateByKind(Kind kind); + WorkflowNode(Type type, Kind kind); virtual ~WorkflowNode() = default; @@ -113,14 +121,17 @@ public: WorkflowNode(WorkflowNode&&) = default; WorkflowNode& operator=(WorkflowNode&&) = default; - Vec2i GetPosition() const; void SetPosition(const Vec2i& position); + Vec2i GetPosition() const; size_t GetId() const; - Type GetType() const; Kind GetKind() const; int GetDepth() const; + Type GetType() const; + bool IsInputNode() const; + bool IsOutputNode() const; + void ConnectInput(int nodeId, WorkflowNode& output, int outputNodeId); void DisconnectInput(int nodeId); bool IsInputConnected(int nodeId) const; @@ -131,6 +142,15 @@ public: virtual void Evaluate(WorkflowEvaluationContext& ctx) = 0; + void Draw(); + virtual void DrawExtra() {} + + void DrawDebugInfo() const; + virtual void DrawExtraDebugInfo() const {} + + virtual void ReadFrom(std::istream& istream); + virtual void WriteTo(std::ostream& ostream); + protected: InputPin& InsertInputPin(int atIdx); void RemoveInputPin(int pin); @@ -153,6 +173,9 @@ private: std::vector<std::unique_ptr<WorkflowNode>> mNodes; std::vector<std::unique_ptr<BaseValue>> mConstants; std::vector<std::vector<size_t>> mDepthGroups; + int mConnectionCount; + int mNodeCount; + int mConstantCount; bool mDepthsDirty = true; public: @@ -190,6 +213,13 @@ public: /// When `getInfo == false, the corresponding error code is returned but without/with empty payloads. GraphUpdateResult UpdateGraph(bool getInfo = true); + enum ReadResult { + ReadSuccess, + ReadInvalidVersion, + }; + ReadResult ReadFrom(std::istream& stream); + void WriteTo(std::ostream& stream); + private: std::pair<WorkflowConnection&, size_t> AllocWorkflowConnection(); std::pair<std::unique_ptr<WorkflowNode>&, size_t> AllocWorkflowStep(); diff --git a/core/src/Model/Workflow/Workflow.cpp b/core/src/Model/Workflow/Workflow_Main.cpp index a1af44a..c8657e8 100644 --- a/core/src/Model/Workflow/Workflow.cpp +++ b/core/src/Model/Workflow/Workflow_Main.cpp @@ -1,8 +1,11 @@ #include "Workflow.hpp" +#include <imgui.h> +#include <imgui_node_editor.h> #include <tsl/robin_set.h> #include <algorithm> #include <cassert> +#include <iostream> #include <queue> #include <utility> @@ -44,6 +47,80 @@ std::span<const WorkflowConnection::ConnectionPoint> WorkflowConnection::GetDest } } +static void DrawConnectionPoints(const std::vector<WorkflowConnection::ConnectionPoint>& points, const char* pinHint) { + ImGui::Indent(32.0f); + for (auto& pt : points) { + ImGui::Text("{ Node = %llu, Pin (%s) = %d }", pt.Node, pinHint, pt.Pin); + if (ImGui::IsItemHovered()) { + // TODO highlight node + } + } + ImGui::Unindent(); +} + +static void DrawConnectionPoint(const WorkflowConnection::ConnectionPoint& point, const char* pinHint) { + ImGui::Indent(32.0f); + ImGui::Text("{ Node = %llu, Pin (%s) = %d }", point.Node, pinHint, point.Pin); + ImGui::Unindent(); +} + +void WorkflowConnection::DrawDebugInfo() const { + ImGui::BeginTooltip(); + switch (ConnectionDirection) { + case ManyToOne: { + ImGui::Text("Type: many-to-one"); + ImGui::Text("Sources:"); + ::DrawConnectionPoints(MultiConnections, "output"); + ImGui::Text("Destination:"); + ::DrawConnectionPoint(SingleConnection, "input"); + } break; + + case OneToMany: { + ImGui::Text("Type: one-to-many"); + ImGui::Text("Source:"); + ::DrawConnectionPoint(SingleConnection, "output"); + ImGui::Text("Destinations:"); + ::DrawConnectionPoints(MultiConnections, "input"); + } break; + } + ImGui::EndTooltip(); +} + +static WorkflowConnection::ConnectionPoint ReadConnectionPoint(std::istream& stream) { + WorkflowConnection::ConnectionPoint pt; + stream >> pt.Node; + stream >> pt.Pin; + return pt; +} + +void WorkflowConnection::ReadFrom(std::istream& stream) { + int n; + stream >> n; + ConnectionDirection = (Direction)n; + + SingleConnection = ::ReadConnectionPoint(stream); + + size_t size; + stream >> size; + for (size_t i = 0; i < size; ++i) { + MultiConnections.push_back(::ReadConnectionPoint(stream)); + } +} + +static void WriteConnectionPoint(std::ostream& stream, const WorkflowConnection::ConnectionPoint& pt) { + stream << pt.Node; + stream << pt.Pin; +} + +void WorkflowConnection::WriteTo(std::ostream& stream) { + stream << (int)ConnectionDirection; + ::WriteConnectionPoint(stream, SingleConnection); + stream << (size_t)MultiConnections.size(); + for (auto& pt : MultiConnections) { + ::WriteConnectionPoint(stream, pt); + } +} + bool WorkflowNode::InputPin::IsConstantConnection() const { return ConnectionToConst && IsConnected(); } @@ -94,12 +171,26 @@ WorkflowNode::Type WorkflowNode::GetType() const { return mType; } +int WorkflowNode::GetDepth() const { + return mDepth; +} + WorkflowNode::Kind WorkflowNode::GetKind() const { - return mKind; + if (IsInputNode()) { + return InputType; + } else if (IsOutputNode()) { + return OutputType; + } else { + return TransformType; + } } -int WorkflowNode::GetDepth() const { - return mDepth; +bool WorkflowNode::IsInputNode() const { + return mInputs.size() == 0; +} + +bool WorkflowNode::IsOutputNode() const { + return mOutputs.size() == 0; } void WorkflowNode::ConnectInput(int nodeId, WorkflowNode& output, int outputNodeId) { @@ -126,6 +217,29 @@ bool WorkflowNode::IsOutputConnected(int nodeId) const { return mOutputs[nodeId].IsConnected(); } +void WorkflowNode::Draw() { +} + +void WorkflowNode::DrawDebugInfo() const { + ImGui::BeginTooltip(); + ImGui::Text("Node kind: %s", FormatKind(mKind)); + ImGui::Text("Node type: %s", FormatType(mType)); + ImGui::Text("Node ID: %llu", mId); + ImGui::Text("Depth: %d", mDepth); + DrawExtraDebugInfo(); + ImGui::EndTooltip(); +} + +void WorkflowNode::ReadFrom(std::istream& stream) { + stream >> mId; + stream >> mPosition.x >> mPosition.y; +} + +void WorkflowNode::WriteTo(std::ostream& stream) { + stream << mId; + stream << mPosition.x << mPosition.y; +} + WorkflowNode::InputPin& WorkflowNode::InsertInputPin(int atIdx) { assert(atIdx >= 0 && atIdx < mInputs.size()); @@ -537,6 +651,92 @@ Workflow::GraphUpdateResult Workflow::UpdateGraph(bool getInfo) { return GraphUpdate_Success{}; } +Workflow::ReadResult Workflow::ReadFrom(std::istream& stream) { + auto DeserializeV0 = [&]() { + size_t connectionsStorage, nodesStorage, constantsStorage; + stream >> connectionsStorage >> nodesStorage >> constantsStorage; + + uint32_t connectionCount, nodeCount, constantCount; + stream >> connectionCount >> nodeCount >> constantCount; + + for (uint32_t i = 0; i < connectionCount; ++i) { + size_t idx; + stream >> idx; + + mConnections[idx].ReadFrom(stream); + } + + for (uint32_t i = 0; i < nodeCount; ++i) { + size_t idx; + stream >> idx; + + uint32_t nKind; + stream >> nKind; + auto kind = (WorkflowNode::Kind)nKind; + + mNodes[idx] = WorkflowNode::CreateByKind(kind); + mNodes[idx]->ReadFrom(stream); + } + + for (uint32_t i = 0; i < constantCount; ++i) { + size_t idx; + stream >> idx; + + uint32_t nKind; + stream >> nKind; + autp kind = (BaseValue::Kind)nKind; + + mConstants[idx] = BaseValue::CreateByKind(kind); + mConstants[idx]->ReadFrom(stream); + } + }; + + uint64_t version; + stream >> version; + + switch (version) { + case 0: DeserializeV0(); break; + default: return ReadInvalidVersion; + } + return ReadSuccess; +} + +void Workflow::WriteTo(std::ostream& stream) { + // Version + stream << (uint64_t)0; + + stream << (size_t)mConnections.size(); + stream << (size_t)mNodes.size(); + stream << (size_t)mConstants.size(); + stream << (uint32_t)mConnectionCount; + stream << (uint32_t)mNodeCount; + stream << (uint32_t)mConstantCount; + + for (size_t i = 0; i < mConnections.size(); ++i) { + auto& conn = mConnections[i]; + if (conn.IsValid()) { + stream << i; + conn.WriteTo(stream); + } + } + + for (size_t i = 0; i < mNodes.size(); ++i) { + auto& node = mNodes[i]; + if (node) { + stream << i << (uint32_t)node->GetKind(); + node->WriteTo(stream); + } + } + + for (size_t i = 0; i < mConstants.size(); ++i) { + auto& constant = mConstants[i]; + if (constant) { + stream << i; + constant->WriteTo(stream); + } + } +} + std::pair<WorkflowConnection&, size_t> Workflow::AllocWorkflowConnection() { for (size_t idx = 0; idx < mConnections.size(); ++idx) { auto& elm = mConnections[idx]; diff --git a/core/src/Model/Workflow/Workflow_RTTI.cpp b/core/src/Model/Workflow/Workflow_RTTI.cpp new file mode 100644 index 0000000..0719372 --- /dev/null +++ b/core/src/Model/Workflow/Workflow_RTTI.cpp @@ -0,0 +1,51 @@ +#include "Workflow.hpp" + +#include "Model/Workflow/Nodes/DocumentNodes.hpp" +#include "Model/Workflow/Nodes/NumericNodes.hpp" +#include "Model/Workflow/Nodes/TextNodes.hpp" +#include "Model/Workflow/Nodes/UserInputNodes.hpp" +#include "Utils/Macros.hpp" + +#include <memory> + +const char* WorkflowNode::FormatKind(Kind kind) { + switch (kind) { + case KD_NumericAddition: return "NumericOperation (addition)"; + case KD_NumericSubtraction: return "NumericOperation (subtraction)"; + case KD_NumericMultiplication: return "NumericOperation (multiplication)"; + case KD_NumericDivision: return "NumericOperation (division)"; + case KD_NumericExpression: return "NumericExpression"; + case KD_TextFormatting: return "TextFormatting"; + case KD_DocumentTemplateExpansion: return "DocumentTemplateExpansion"; + case KD_FormInput: return "FormInput"; + case KD_DatabaseRowsInput: return "DatabaseRowsInput"; + + case InvalidKind: UNREACHABLE; + } +} + +const char* WorkflowNode::FormatType(Type type) { + switch (type) { + case InputType: return "input"; + case TransformType: return "transform"; + case OutputType: return "output"; + default: UNREACHABLE; + } +} + +std::unique_ptr<WorkflowNode> WorkflowNode::CreateByKind(WorkflowNode::Kind kind) { + switch (kind) { + case KD_NumericAddition: return std::make_unique<NumericOperationNode>(NumericOperationNode::Addition); + case KD_NumericSubtraction: return std::make_unique<NumericOperationNode>(NumericOperationNode::Subtraction); + case KD_NumericMultiplication: return std::make_unique<NumericOperationNode>(NumericOperationNode::Multiplication); + case KD_NumericDivision: return std::make_unique<NumericOperationNode>(NumericOperationNode::Division); + + case KD_NumericExpression: return std::make_unique<NumericExpressionNode>(); + case KD_TextFormatting: return std::make_unique<TextFormatterNode>(); + case KD_DocumentTemplateExpansion: return std::make_unique<DocumentTemplateExpansionNode>(); + case KD_FormInput: return std::make_unique<FormInputNode>(); + case KD_DatabaseRowsInput: return std::make_unique<DatabaseRowsInputNode>(); + + case InvalidKind: return nullptr; + } +} |