summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-04-26 14:07:28 -0700
committerrtk0c <[email protected]>2021-04-26 14:07:28 -0700
commitb7d5b514e7bffd3149a99bc7f1424f8251876d85 (patch)
tree42f2867875c0b367fab2a6db7be395f8c777eb41 /core/src
parente7afe82857ac3ccc3e10b40cee60ea94cc59232b (diff)
Serialization for workflow stuff
Diffstat (limited to 'core/src')
-rw-r--r--core/src/Model/Workflow/Evaluation.cpp34
-rw-r--r--core/src/Model/Workflow/Evaluation.hpp6
-rw-r--r--core/src/Model/Workflow/Value.cpp9
-rw-r--r--core/src/Model/Workflow/Value.hpp17
-rw-r--r--core/src/Model/Workflow/Value_Main.cpp19
-rw-r--r--core/src/Model/Workflow/Value_RTTI.cpp22
-rw-r--r--core/src/Model/Workflow/Workflow.hpp40
-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.cpp51
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;
+ }
+}