aboutsummaryrefslogtreecommitdiff
path: root/src/formatter
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2021-05-07 02:18:07 +0300
committerEvgeny Zinoviev <me@ch1p.io>2021-05-07 02:18:07 +0300
commit7e743b73433475df086fcec81be7b10c1d695a42 (patch)
tree1737c5f9bdad2a40f740e9a655e510641331b9e2 /src/formatter
initial
Diffstat (limited to 'src/formatter')
-rw-r--r--src/formatter/formatter.cc38
-rw-r--r--src/formatter/formatter.h257
2 files changed, 295 insertions, 0 deletions
diff --git a/src/formatter/formatter.cc b/src/formatter/formatter.cc
new file mode 100644
index 0000000..6fedf8c
--- /dev/null
+++ b/src/formatter/formatter.cc
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include "formatter.h"
+
+namespace formatter {
+
+std::ostream& operator<<(std::ostream& os, Unit val) {
+ switch (val) {
+ case Unit::V:
+ return os << "V";
+
+ case Unit::A:
+ return os << "A";
+
+ case Unit::Wh:
+ return os << "Wh";
+
+ case Unit::VA:
+ return os << "VA";
+
+ case Unit::Hz:
+ return os << "Hz";
+
+ case Unit::Percentage:
+ return os << "%";
+
+ case Unit::Celsius:
+ return os << "°C";
+
+ default:
+ break;
+ };
+
+ return os;
+}
+
+
+} \ No newline at end of file
diff --git a/src/formatter/formatter.h b/src/formatter/formatter.h
new file mode 100644
index 0000000..5dfa184
--- /dev/null
+++ b/src/formatter/formatter.h
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: BSD-3-Clause
+
+#ifndef INVERTER_TOOLS_PRINT_H
+#define INVERTER_TOOLS_PRINT_H
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <ios>
+#include <iomanip>
+#include <nlohmann/json.hpp>
+
+#include "src/util.h"
+
+namespace formatter {
+
+using nlohmann::json;
+using nlohmann::ordered_json;
+
+
+/**
+ * Enumerations
+ */
+
+enum class Unit {
+ None = 0,
+ V,
+ A,
+ Wh,
+ VA,
+ Hz,
+ Percentage,
+ Celsius,
+};
+
+enum class Format {
+ Table,
+ SimpleTable,
+ JSON,
+};
+std::ostream& operator<<(std::ostream& os, Unit val);
+
+
+/**
+ * Helper functions
+ */
+
+template <typename T>
+std::string to_str(T& v) {
+ std::ostringstream buf;
+ buf << v;
+ return buf.str();
+}
+
+
+/**
+ * Items
+ */
+
+template <typename T>
+struct TableItem {
+ explicit TableItem(std::string key, std::string title, T value, Unit unit = Unit::None, unsigned precision = 0) :
+ key(std::move(key)),
+ title(std::move(title)),
+ value(value),
+ unit(unit) {}
+
+ std::string key;
+ std::string title;
+ T value;
+ Unit unit;
+};
+
+template <typename T>
+struct ListItem {
+ explicit ListItem(T value) : value(value) {}
+ T value;
+};
+
+
+/**
+ * Items holders
+ */
+
+class Formattable {
+protected:
+ Format format_;
+
+public:
+ explicit Formattable(Format format) : format_(format) {}
+ virtual ~Formattable() = default;
+
+ virtual std::ostream& writeJSON(std::ostream& os) const = 0;
+ virtual std::ostream& writeTable(std::ostream& os) const = 0;
+ virtual std::ostream& writeSimpleTable(std::ostream& os) const = 0;
+
+ friend std::ostream& operator<<(std::ostream& os, Formattable const& ref) {
+ switch (ref.format_) {
+ case Format::Table:
+ return ref.writeTable(os);
+
+ case Format::SimpleTable:
+ return ref.writeSimpleTable(os);
+
+ case Format::JSON:
+ return ref.writeJSON(os);
+ }
+
+ return os;
+ }
+};
+
+
+// T must have `operator<<` and `basic_json toJSON()` methods
+template <typename T>
+class Table : public Formattable {
+protected:
+ std::vector<TableItem<T>> v_;
+
+public:
+ explicit Table(Format format, std::vector<TableItem<T>> v)
+ : Formattable(format), v_(v) {}
+
+ std::ostream& writeSimpleTable(std::ostream& os) const override {
+ for (const auto& item: v_) {
+ os << item.key << " ";
+
+ std::string value = to_str(item.value);
+ bool space = string_has(value, ' ');
+ if (space)
+ os << "\"";
+ os << value;
+ if (space)
+ os << "\"";
+
+ if (item.unit != Unit::None)
+ os << " " << item.unit;
+
+ if (&item != &v_.back())
+ os << std::endl;
+ }
+ return os;
+ }
+
+ std::ostream& writeTable(std::ostream& os) const override {
+ int maxWidth = 0;
+ for (const auto& item: v_) {
+ int width = item.title.size()+1 /* colon */;
+ if (width > maxWidth)
+ maxWidth = width;
+ }
+
+ std::ios_base::fmtflags f(os.flags());
+ os << std::left;
+ for (const auto &item: v_) {
+ os << std::setw(maxWidth) << (item.title+":") << " " << item.value;
+
+ if (item.unit != Unit::None)
+ os << " " << item.unit;
+
+ if (&item != &v_.back())
+ os << std::endl;
+ }
+
+ os.flags(f);
+ return os;
+ }
+
+ std::ostream& writeJSON(std::ostream& os) const override {
+ ordered_json j = {
+ {"result", "ok"},
+ {"data", {}}
+ };
+ for (const auto &item: v_) {
+ if (item.unit != Unit::None) {
+ json jval = json::object();
+ jval["value"] = item.value.toJSON();
+ jval["unit"] = to_str(item.unit);
+ j["data"][item.key] = jval;
+ } else {
+ j["data"][item.key] = item.value.toJSON();
+ }
+ }
+ return os << j.dump();
+ }
+};
+
+template <typename T>
+class List : public Formattable {
+protected:
+ std::vector<ListItem<T>> v_;
+
+public:
+ explicit List(Format format, std::vector<ListItem<T>> v)
+ : Formattable(format), v_(v) {}
+
+ std::ostream& writeSimpleTable(std::ostream& os) const override {
+ return writeTable(os);
+ }
+
+ std::ostream& writeTable(std::ostream& os) const override {
+ for (const auto &item: v_) {
+ os << item.value;
+ if (&item != &v_.back())
+ os << std::endl;
+ }
+ return os;
+ }
+
+ std::ostream& writeJSON(std::ostream& os) const override {
+ json data = {};
+ ordered_json j;
+
+ j["result"] = "ok";
+
+ for (const auto &item: v_)
+ data.push_back(item.value.toJSON());
+ j["data"] = data;
+
+ return os << j.dump();
+ }
+};
+
+class Status : public Formattable {
+protected:
+ bool value_;
+ std::string message_;
+
+public:
+ explicit Status(Format format, bool value, std::string message)
+ : Formattable(format), value_(value), message_(std::move(message)) {}
+
+ std::ostream& writeSimpleTable(std::ostream& os) const override {
+ return writeTable(os);
+ }
+
+ std::ostream& writeTable(std::ostream& os) const override {
+ os << (value_ ? "ok" : "error");
+ if (!message_.empty())
+ os << ": " << message_;
+ return os;
+ }
+
+ std::ostream& writeJSON(std::ostream& os) const override {
+ ordered_json j = {
+ {"result", (value_ ? "ok" : "error")}
+ };
+ if (!message_.empty())
+ j["message"] = message_;
+ return os << j.dump();
+ }
+};
+
+}
+
+#endif \ No newline at end of file