294 lines
6.5 KiB
C++
294 lines
6.5 KiB
C++
// 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,
|
|
SimpleJSON,
|
|
};
|
|
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& writeSimpleJSON(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);
|
|
|
|
case Format::SimpleJSON:
|
|
return ref.writeSimpleJSON(os);
|
|
}
|
|
|
|
return os;
|
|
}
|
|
};
|
|
|
|
|
|
// T must have `operator<<`, `json toJSON()` and `json toSimpleJSON()` 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) {}
|
|
|
|
void push(TableItem<T> item) {
|
|
v_.push_back(item);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
std::ostream& writeSimpleJSON(std::ostream& os) const override {
|
|
ordered_json j = {
|
|
{"result", "ok"},
|
|
{"data", {}}
|
|
};
|
|
for (const auto &item: v_) {
|
|
j["data"][item.key] = item.value.toSimpleJSON();
|
|
}
|
|
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();
|
|
}
|
|
|
|
std::ostream& writeSimpleJSON(std::ostream& os) const override {
|
|
json data = {};
|
|
ordered_json j;
|
|
|
|
j["result"] = "ok";
|
|
|
|
for (const auto &item: v_)
|
|
data.push_back(item.value.toSimpleJSON());
|
|
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();
|
|
}
|
|
|
|
std::ostream& writeSimpleJSON(std::ostream& os) const override {
|
|
return writeJSON(os);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif |