mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
refactor: adapt magic_enum to Qt (#5258)
This commit is contained in:
parent
044d457d20
commit
ed20e71db4
|
@ -188,6 +188,7 @@
|
||||||
- Dev: Cleaned up and optimized resources. (#5222)
|
- Dev: Cleaned up and optimized resources. (#5222)
|
||||||
- Dev: Refactor `StreamerMode`. (#5216, #5236)
|
- Dev: Refactor `StreamerMode`. (#5216, #5236)
|
||||||
- Dev: Cleaned up unused code in `MessageElement` and `MessageLayoutElement`. (#5225)
|
- Dev: Cleaned up unused code in `MessageElement` and `MessageLayoutElement`. (#5225)
|
||||||
|
- Dev: Adapted `magic_enum` to Qt's Utf-16 strings. (#5258)
|
||||||
- Dev: `NetworkManager`'s statics are now created in its `init` method. (#5254)
|
- Dev: `NetworkManager`'s statics are now created in its `init` method. (#5254)
|
||||||
|
|
||||||
## 2.4.6
|
## 2.4.6
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <pajlada/settings.hpp>
|
#include <pajlada/settings.hpp>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
@ -108,10 +109,7 @@ public:
|
||||||
template <typename T2>
|
template <typename T2>
|
||||||
EnumStringSetting<Enum> &operator=(Enum newValue)
|
EnumStringSetting<Enum> &operator=(Enum newValue)
|
||||||
{
|
{
|
||||||
std::string enumName(magic_enum::enum_name(newValue));
|
this->setValue(qmagicenum::enumNameString(newValue).toLower());
|
||||||
auto qEnumName = QString::fromStdString(enumName);
|
|
||||||
|
|
||||||
this->setValue(qEnumName.toLower());
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -130,8 +128,8 @@ public:
|
||||||
|
|
||||||
Enum getEnum()
|
Enum getEnum()
|
||||||
{
|
{
|
||||||
return magic_enum::enum_cast<Enum>(this->getValue().toStdString(),
|
return qmagicenum::enumCast<Enum>(this->getValue(),
|
||||||
magic_enum::case_insensitive)
|
qmagicenum::CASE_INSENSITIVE)
|
||||||
.value_or(this->defaultValue);
|
.value_or(this->defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "util/AbandonObject.hpp"
|
#include "util/AbandonObject.hpp"
|
||||||
#include "util/DebugCount.hpp"
|
#include "util/DebugCount.hpp"
|
||||||
#include "util/PostToThread.hpp"
|
#include "util/PostToThread.hpp"
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include <magic_enum/magic_enum.hpp>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
@ -181,11 +182,9 @@ void NetworkData::emitFinally()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QLatin1String NetworkData::typeString() const
|
QString NetworkData::typeString() const
|
||||||
{
|
{
|
||||||
auto view = magic_enum::enum_name<NetworkRequestType>(this->requestType);
|
return qmagicenum::enumNameString(this->requestType);
|
||||||
return QLatin1String{view.data(),
|
|
||||||
static_cast<QLatin1String::size_type>(view.size())};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(std::shared_ptr<NetworkData> &&data)
|
void load(std::shared_ptr<NetworkData> &&data)
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
void emitError(NetworkResult &&result);
|
void emitError(NetworkResult &&result);
|
||||||
void emitFinally();
|
void emitFinally();
|
||||||
|
|
||||||
QLatin1String typeString() const;
|
QString typeString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString hash_;
|
QString hash_;
|
||||||
|
|
|
@ -30,11 +30,7 @@ QString sendAnnouncementColor(const CommandContext &ctx,
|
||||||
QString colorStr = "";
|
QString colorStr = "";
|
||||||
if (color != HelixAnnouncementColor::Primary)
|
if (color != HelixAnnouncementColor::Primary)
|
||||||
{
|
{
|
||||||
colorStr =
|
colorStr = qmagicenum::enumNameString(color).toLower();
|
||||||
QString::fromStdString(
|
|
||||||
std::string{
|
|
||||||
magic_enum::enum_name<HelixAnnouncementColor>(color)})
|
|
||||||
.toLower();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.words.size() < 2)
|
if (ctx.words.size() < 2)
|
||||||
|
|
|
@ -119,9 +119,12 @@ int c2_register_callback(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callbackSavedName = QString("c2cb-%1").arg(
|
auto typeName = magic_enum::enum_name(evtType);
|
||||||
magic_enum::enum_name<EventType>(evtType).data());
|
std::string callbackSavedName;
|
||||||
lua_setfield(L, LUA_REGISTRYINDEX, callbackSavedName.toStdString().c_str());
|
callbackSavedName.reserve(5 + typeName.size());
|
||||||
|
callbackSavedName += "c2cb-";
|
||||||
|
callbackSavedName += typeName;
|
||||||
|
lua_setfield(L, LUA_REGISTRYINDEX, callbackSavedName.c_str());
|
||||||
|
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
# include "common/QLogging.hpp"
|
# include "common/QLogging.hpp"
|
||||||
# include "controllers/commands/CommandController.hpp"
|
# include "controllers/commands/CommandController.hpp"
|
||||||
|
# include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# include <lua.h>
|
# include <lua.h>
|
||||||
|
@ -26,7 +27,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else if (!homepageObj.isUndefined())
|
else if (!homepageObj.isUndefined())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(homepageObj.type()).data();
|
auto type = qmagicenum::enumName(homepageObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("homepage is defined but is not a string (its type is %1)")
|
QString("homepage is defined but is not a string (its type is %1)")
|
||||||
.arg(type));
|
.arg(type));
|
||||||
|
@ -38,7 +39,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(nameObj.type()).data();
|
auto type = qmagicenum::enumName(nameObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("name is not a string (its type is %1)").arg(type));
|
QString("name is not a string (its type is %1)").arg(type));
|
||||||
}
|
}
|
||||||
|
@ -50,7 +51,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(descrObj.type()).data();
|
auto type = qmagicenum::enumName(descrObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("description is not a string (its type is %1)").arg(type));
|
QString("description is not a string (its type is %1)").arg(type));
|
||||||
}
|
}
|
||||||
|
@ -64,7 +65,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
const auto &t = authorsArr.at(i);
|
const auto &t = authorsArr.at(i);
|
||||||
if (!t.isString())
|
if (!t.isString())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(t.type()).data();
|
auto type = qmagicenum::enumName(t.type());
|
||||||
this->errors.push_back(
|
this->errors.push_back(
|
||||||
QString("authors element #%1 is not a string (it is a %2)")
|
QString("authors element #%1 is not a string (it is a %2)")
|
||||||
.arg(i)
|
.arg(i)
|
||||||
|
@ -76,7 +77,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(authorsObj.type()).data();
|
auto type = qmagicenum::enumName(authorsObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("authors is not an array (its type is %1)").arg(type));
|
QString("authors is not an array (its type is %1)").arg(type));
|
||||||
}
|
}
|
||||||
|
@ -88,7 +89,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(licenseObj.type()).data();
|
auto type = qmagicenum::enumName(licenseObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("license is not a string (its type is %1)").arg(type));
|
QString("license is not a string (its type is %1)").arg(type));
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(verObj.type()).data();
|
auto type = qmagicenum::enumName(verObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("version is not a string (its type is %1)").arg(type));
|
QString("version is not a string (its type is %1)").arg(type));
|
||||||
this->version = semver::version(0, 0, 0);
|
this->version = semver::version(0, 0, 0);
|
||||||
|
@ -119,7 +120,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
if (!permsObj.isArray())
|
if (!permsObj.isArray())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(permsObj.type()).data();
|
auto type = qmagicenum::enumName(permsObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("permissions is not an array (its type is %1)")
|
QString("permissions is not an array (its type is %1)")
|
||||||
.arg(type));
|
.arg(type));
|
||||||
|
@ -132,7 +133,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
const auto &t = permsArr.at(i);
|
const auto &t = permsArr.at(i);
|
||||||
if (!t.isObject())
|
if (!t.isObject())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(t.type()).data();
|
auto type = qmagicenum::enumName(t.type());
|
||||||
this->errors.push_back(QString("permissions element #%1 is not "
|
this->errors.push_back(QString("permissions element #%1 is not "
|
||||||
"an object (its type is %2)")
|
"an object (its type is %2)")
|
||||||
.arg(i)
|
.arg(i)
|
||||||
|
@ -161,7 +162,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
if (!tagsObj.isArray())
|
if (!tagsObj.isArray())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(tagsObj.type()).data();
|
auto type = qmagicenum::enumName(tagsObj.type());
|
||||||
this->errors.emplace_back(
|
this->errors.emplace_back(
|
||||||
QString("tags is not an array (its type is %1)").arg(type));
|
QString("tags is not an array (its type is %1)").arg(type));
|
||||||
return;
|
return;
|
||||||
|
@ -173,7 +174,7 @@ PluginMeta::PluginMeta(const QJsonObject &obj)
|
||||||
const auto &t = tagsArr.at(i);
|
const auto &t = tagsArr.at(i);
|
||||||
if (!t.isString())
|
if (!t.isString())
|
||||||
{
|
{
|
||||||
QString type = magic_enum::enum_name(t.type()).data();
|
auto type = qmagicenum::enumName(t.type());
|
||||||
this->errors.push_back(
|
this->errors.push_back(
|
||||||
QString("tags element #%1 is not a string (its type is %2)")
|
QString("tags element #%1 is not a string (its type is %2)")
|
||||||
.arg(i)
|
.arg(i)
|
||||||
|
|
|
@ -107,14 +107,14 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
// this uses magic enum to help automatic tooling find usages
|
// this uses magic enum to help automatic tooling find usages
|
||||||
|
auto typeName =
|
||||||
|
magic_enum::enum_name(lua::api::EventType::CompletionRequested);
|
||||||
|
std::string cbName;
|
||||||
|
cbName.reserve(5 + typeName.size());
|
||||||
|
cbName += "c2cb-";
|
||||||
|
cbName += typeName;
|
||||||
auto typ =
|
auto typ =
|
||||||
lua_getfield(this->state_, LUA_REGISTRYINDEX,
|
lua_getfield(this->state_, LUA_REGISTRYINDEX, cbName.c_str());
|
||||||
QString("c2cb-%1")
|
|
||||||
.arg(magic_enum::enum_name<lua::api::EventType>(
|
|
||||||
lua::api::EventType::CompletionRequested)
|
|
||||||
.data())
|
|
||||||
.toStdString()
|
|
||||||
.c_str());
|
|
||||||
if (typ != LUA_TFUNCTION)
|
if (typ != LUA_TFUNCTION)
|
||||||
{
|
{
|
||||||
lua_pop(this->state_, 1);
|
lua_pop(this->state_, 1);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
# include "controllers/plugins/PluginPermission.hpp"
|
# include "controllers/plugins/PluginPermission.hpp"
|
||||||
|
|
||||||
|
# include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
# include <magic_enum/magic_enum.hpp>
|
# include <magic_enum/magic_enum.hpp>
|
||||||
# include <QJsonObject>
|
# include <QJsonObject>
|
||||||
|
|
||||||
|
@ -11,14 +13,13 @@ PluginPermission::PluginPermission(const QJsonObject &obj)
|
||||||
auto jsontype = obj.value("type");
|
auto jsontype = obj.value("type");
|
||||||
if (!jsontype.isString())
|
if (!jsontype.isString())
|
||||||
{
|
{
|
||||||
QString tn = magic_enum::enum_name(jsontype.type()).data();
|
auto tn = qmagicenum::enumName(jsontype.type());
|
||||||
this->errors.emplace_back(QString("permission type is defined but is "
|
this->errors.emplace_back(QString("permission type is defined but is "
|
||||||
"not a string (its type is %1)")
|
"not a string (its type is %1)")
|
||||||
.arg(tn));
|
.arg(tn));
|
||||||
}
|
}
|
||||||
auto strtype = jsontype.toString().toStdString();
|
auto opt = qmagicenum::enumCast<PluginPermission::Type>(
|
||||||
auto opt = magic_enum::enum_cast<PluginPermission::Type>(
|
jsontype.toString(), qmagicenum::CASE_INSENSITIVE);
|
||||||
strtype, magic_enum::case_insensitive);
|
|
||||||
if (!opt.has_value())
|
if (!opt.has_value())
|
||||||
{
|
{
|
||||||
this->errors.emplace_back(QString("permission type is an unknown (%1)")
|
this->errors.emplace_back(QString("permission type is an unknown (%1)")
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "providers/seventv/eventapi/Message.hpp"
|
#include "providers/seventv/eventapi/Message.hpp"
|
||||||
#include "providers/seventv/SeventvBadges.hpp"
|
#include "providers/seventv/SeventvBadges.hpp"
|
||||||
#include "providers/seventv/SeventvCosmetics.hpp"
|
#include "providers/seventv/SeventvCosmetics.hpp"
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
@ -228,7 +229,7 @@ void SeventvEventAPI::handleDispatch(const Dispatch &dispatch)
|
||||||
default: {
|
default: {
|
||||||
qCDebug(chatterinoSeventvEventAPI)
|
qCDebug(chatterinoSeventvEventAPI)
|
||||||
<< "Unknown subscription type:"
|
<< "Unknown subscription type:"
|
||||||
<< magic_enum::enum_name(dispatch.type).data()
|
<< qmagicenum::enumName(dispatch.type)
|
||||||
<< "body:" << dispatch.body;
|
<< "body:" << dispatch.body;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/seventv/eventapi/Dispatch.hpp"
|
#include "providers/seventv/eventapi/Dispatch.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -7,8 +9,7 @@
|
||||||
namespace chatterino::seventv::eventapi {
|
namespace chatterino::seventv::eventapi {
|
||||||
|
|
||||||
Dispatch::Dispatch(QJsonObject obj)
|
Dispatch::Dispatch(QJsonObject obj)
|
||||||
: type(magic_enum::enum_cast<SubscriptionType>(
|
: type(qmagicenum::enumCast<SubscriptionType>(obj["type"].toString())
|
||||||
obj["type"].toString().toStdString())
|
|
||||||
.value_or(SubscriptionType::INVALID))
|
.value_or(SubscriptionType::INVALID))
|
||||||
, body(obj["body"].toObject())
|
, body(obj["body"].toObject())
|
||||||
, id(this->body["id"].toString())
|
, id(this->body["id"].toString())
|
||||||
|
@ -95,8 +96,8 @@ bool UserConnectionUpdateDispatch::validate() const
|
||||||
|
|
||||||
CosmeticCreateDispatch::CosmeticCreateDispatch(const Dispatch &dispatch)
|
CosmeticCreateDispatch::CosmeticCreateDispatch(const Dispatch &dispatch)
|
||||||
: data(dispatch.body["object"]["data"].toObject())
|
: data(dispatch.body["object"]["data"].toObject())
|
||||||
, kind(magic_enum::enum_cast<CosmeticKind>(
|
, kind(qmagicenum::enumCast<CosmeticKind>(
|
||||||
dispatch.body["object"]["kind"].toString().toStdString())
|
dispatch.body["object"]["kind"].toString())
|
||||||
.value_or(CosmeticKind::INVALID))
|
.value_or(CosmeticKind::INVALID))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -111,8 +112,7 @@ EntitlementCreateDeleteDispatch::EntitlementCreateDeleteDispatch(
|
||||||
{
|
{
|
||||||
const auto obj = dispatch.body["object"].toObject();
|
const auto obj = dispatch.body["object"].toObject();
|
||||||
this->refID = obj["ref_id"].toString();
|
this->refID = obj["ref_id"].toString();
|
||||||
this->kind = magic_enum::enum_cast<CosmeticKind>(
|
this->kind = qmagicenum::enumCast<CosmeticKind>(obj["kind"].toString())
|
||||||
obj["kind"].toString().toStdString())
|
|
||||||
.value_or(CosmeticKind::INVALID);
|
.value_or(CosmeticKind::INVALID);
|
||||||
|
|
||||||
const auto userConnections = obj["user"]["connections"].toArray();
|
const auto userConnections = obj["user"]["connections"].toArray();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/seventv/eventapi/Subscription.hpp"
|
#include "providers/seventv/eventapi/Subscription.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
@ -9,14 +11,15 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using namespace chatterino;
|
||||||
using namespace chatterino::seventv::eventapi;
|
using namespace chatterino::seventv::eventapi;
|
||||||
|
|
||||||
const char *typeToString(SubscriptionType type)
|
QString typeToString(SubscriptionType type)
|
||||||
{
|
{
|
||||||
return magic_enum::enum_name(type).data();
|
return qmagicenum::enumNameString(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject createDataJson(const char *typeName, const Condition &condition)
|
QJsonObject createDataJson(const QString &typeName, const Condition &condition)
|
||||||
{
|
{
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
data["type"] = typeName;
|
data["type"] = typeName;
|
||||||
|
@ -45,7 +48,7 @@ bool Subscription::operator!=(const Subscription &rhs) const
|
||||||
|
|
||||||
QByteArray Subscription::encodeSubscribe() const
|
QByteArray Subscription::encodeSubscribe() const
|
||||||
{
|
{
|
||||||
const auto *typeName = typeToString(this->type);
|
auto typeName = typeToString(this->type);
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root["op"] = (int)Opcode::Subscribe;
|
root["op"] = (int)Opcode::Subscribe;
|
||||||
root["d"] = createDataJson(typeName, this->condition);
|
root["d"] = createDataJson(typeName, this->condition);
|
||||||
|
@ -54,7 +57,7 @@ QByteArray Subscription::encodeSubscribe() const
|
||||||
|
|
||||||
QByteArray Subscription::encodeUnsubscribe() const
|
QByteArray Subscription::encodeUnsubscribe() const
|
||||||
{
|
{
|
||||||
const auto *typeName = typeToString(this->type);
|
auto typeName = typeToString(this->type);
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root["op"] = (int)Opcode::Unsubscribe;
|
root["op"] = (int)Opcode::Unsubscribe;
|
||||||
root["d"] = createDataJson(typeName, this->condition);
|
root["d"] = createDataJson(typeName, this->condition);
|
||||||
|
@ -66,8 +69,7 @@ QDebug &operator<<(QDebug &dbg, const Subscription &subscription)
|
||||||
std::visit(
|
std::visit(
|
||||||
[&](const auto &cond) {
|
[&](const auto &cond) {
|
||||||
dbg << "Subscription{ condition:" << cond
|
dbg << "Subscription{ condition:" << cond
|
||||||
<< "type:" << magic_enum::enum_name(subscription.type).data()
|
<< "type:" << qmagicenum::enumName(subscription.type) << '}';
|
||||||
<< '}';
|
|
||||||
},
|
},
|
||||||
subscription.condition);
|
subscription.condition);
|
||||||
return dbg;
|
return dbg;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "common/network/NetworkResult.hpp"
|
#include "common/network/NetworkResult.hpp"
|
||||||
#include "common/QLogging.hpp"
|
#include "common/QLogging.hpp"
|
||||||
#include "util/CancellationToken.hpp"
|
#include "util/CancellationToken.hpp"
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include <magic_enum/magic_enum.hpp>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
@ -1172,9 +1173,7 @@ void Helix::sendChatAnnouncement(
|
||||||
|
|
||||||
QJsonObject body;
|
QJsonObject body;
|
||||||
body.insert("message", message);
|
body.insert("message", message);
|
||||||
const auto colorStr =
|
body.insert("color", qmagicenum::enumNameString(color).toLower());
|
||||||
std::string{magic_enum::enum_name<HelixAnnouncementColor>(color)};
|
|
||||||
body.insert("color", QString::fromStdString(colorStr).toLower());
|
|
||||||
|
|
||||||
this->makePost("chat/announcements", urlQuery)
|
this->makePost("chat/announcements", urlQuery)
|
||||||
.json(body)
|
.json(body)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/twitch/pubsubmessages/AutoMod.hpp"
|
#include "providers/twitch/pubsubmessages/AutoMod.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PubSubAutoModQueueMessage::PubSubAutoModQueueMessage(const QJsonObject &root)
|
PubSubAutoModQueueMessage::PubSubAutoModQueueMessage(const QJsonObject &root)
|
||||||
|
@ -7,7 +9,7 @@ PubSubAutoModQueueMessage::PubSubAutoModQueueMessage(const QJsonObject &root)
|
||||||
, data(root.value("data").toObject())
|
, data(root.value("data").toObject())
|
||||||
, status(this->data.value("status").toString())
|
, status(this->data.value("status").toString())
|
||||||
{
|
{
|
||||||
auto oType = magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
if (oType.has_value())
|
if (oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/twitch/pubsubmessages/Base.hpp"
|
#include "providers/twitch/pubsubmessages/Base.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PubSubMessage::PubSubMessage(QJsonObject _object)
|
PubSubMessage::PubSubMessage(QJsonObject _object)
|
||||||
|
@ -9,7 +11,7 @@ PubSubMessage::PubSubMessage(QJsonObject _object)
|
||||||
, error(this->object.value("error").toString())
|
, error(this->object.value("error").toString())
|
||||||
, typeString(this->object.value("type").toString())
|
, typeString(this->object.value("type").toString())
|
||||||
{
|
{
|
||||||
auto oType = magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
if (oType.has_value())
|
if (oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/twitch/pubsubmessages/ChannelPoints.hpp"
|
#include "providers/twitch/pubsubmessages/ChannelPoints.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PubSubCommunityPointsChannelV1Message::PubSubCommunityPointsChannelV1Message(
|
PubSubCommunityPointsChannelV1Message::PubSubCommunityPointsChannelV1Message(
|
||||||
|
@ -7,7 +9,7 @@ PubSubCommunityPointsChannelV1Message::PubSubCommunityPointsChannelV1Message(
|
||||||
: typeString(root.value("type").toString())
|
: typeString(root.value("type").toString())
|
||||||
, data(root.value("data").toObject())
|
, data(root.value("data").toObject())
|
||||||
{
|
{
|
||||||
auto oType = magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
if (oType.has_value())
|
if (oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/twitch/pubsubmessages/ChatModeratorAction.hpp"
|
#include "providers/twitch/pubsubmessages/ChatModeratorAction.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PubSubChatModeratorActionMessage::PubSubChatModeratorActionMessage(
|
PubSubChatModeratorActionMessage::PubSubChatModeratorActionMessage(
|
||||||
|
@ -7,7 +9,7 @@ PubSubChatModeratorActionMessage::PubSubChatModeratorActionMessage(
|
||||||
: typeString(root.value("type").toString())
|
: typeString(root.value("type").toString())
|
||||||
, data(root.value("data").toObject())
|
, data(root.value("data").toObject())
|
||||||
{
|
{
|
||||||
auto oType = magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
if (oType.has_value())
|
if (oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "providers/twitch/pubsubmessages/LowTrustUsers.hpp"
|
#include "providers/twitch/pubsubmessages/LowTrustUsers.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
|
@ -8,8 +10,7 @@ namespace chatterino {
|
||||||
PubSubLowTrustUsersMessage::PubSubLowTrustUsersMessage(const QJsonObject &root)
|
PubSubLowTrustUsersMessage::PubSubLowTrustUsersMessage(const QJsonObject &root)
|
||||||
: typeString(root.value("type").toString())
|
: typeString(root.value("type").toString())
|
||||||
{
|
{
|
||||||
if (const auto oType =
|
if (const auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
|
||||||
oType.has_value())
|
oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
@ -75,8 +76,8 @@ PubSubLowTrustUsersMessage::PubSubLowTrustUsersMessage(const QJsonObject &root)
|
||||||
this->updatedByUserDisplayName = updatedBy.value("display_name").toString();
|
this->updatedByUserDisplayName = updatedBy.value("display_name").toString();
|
||||||
|
|
||||||
this->treatmentString = data.value("treatment").toString();
|
this->treatmentString = data.value("treatment").toString();
|
||||||
if (const auto oTreatment = magic_enum::enum_cast<Treatment>(
|
if (const auto oTreatment =
|
||||||
this->treatmentString.toStdString());
|
qmagicenum::enumCast<Treatment>(this->treatmentString);
|
||||||
oTreatment.has_value())
|
oTreatment.has_value())
|
||||||
{
|
{
|
||||||
this->treatment = oTreatment.value();
|
this->treatment = oTreatment.value();
|
||||||
|
@ -84,8 +85,8 @@ PubSubLowTrustUsersMessage::PubSubLowTrustUsersMessage(const QJsonObject &root)
|
||||||
|
|
||||||
this->evasionEvaluationString =
|
this->evasionEvaluationString =
|
||||||
data.value("ban_evasion_evaluation").toString();
|
data.value("ban_evasion_evaluation").toString();
|
||||||
if (const auto oEvaluation = magic_enum::enum_cast<EvasionEvaluation>(
|
if (const auto oEvaluation = qmagicenum::enumCast<EvasionEvaluation>(
|
||||||
this->evasionEvaluationString.toStdString());
|
this->evasionEvaluationString);
|
||||||
oEvaluation.has_value())
|
oEvaluation.has_value())
|
||||||
{
|
{
|
||||||
this->evasionEvaluation = oEvaluation.value();
|
this->evasionEvaluation = oEvaluation.value();
|
||||||
|
@ -93,8 +94,8 @@ PubSubLowTrustUsersMessage::PubSubLowTrustUsersMessage(const QJsonObject &root)
|
||||||
|
|
||||||
for (const auto &rType : data.value("types").toArray())
|
for (const auto &rType : data.value("types").toArray())
|
||||||
{
|
{
|
||||||
if (const auto oRestriction = magic_enum::enum_cast<RestrictionType>(
|
if (const auto oRestriction =
|
||||||
rType.toString().toStdString());
|
qmagicenum::enumCast<RestrictionType>(rType.toString());
|
||||||
oRestriction.has_value())
|
oRestriction.has_value())
|
||||||
{
|
{
|
||||||
this->restrictionTypes.set(oRestriction.value());
|
this->restrictionTypes.set(oRestriction.value());
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#include "providers/twitch/pubsubmessages/Whisper.hpp"
|
#include "providers/twitch/pubsubmessages/Whisper.hpp"
|
||||||
|
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
PubSubWhisperMessage::PubSubWhisperMessage(const QJsonObject &root)
|
PubSubWhisperMessage::PubSubWhisperMessage(const QJsonObject &root)
|
||||||
: typeString(root.value("type").toString())
|
: typeString(root.value("type").toString())
|
||||||
{
|
{
|
||||||
auto oType = magic_enum::enum_cast<Type>(this->typeString.toStdString());
|
auto oType = qmagicenum::enumCast<Type>(this->typeString);
|
||||||
if (oType.has_value())
|
if (oType.has_value())
|
||||||
{
|
{
|
||||||
this->type = oType.value();
|
this->type = oType.value();
|
||||||
|
|
313
src/util/QMagicEnum.hpp
Normal file
313
src/util/QMagicEnum.hpp
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringView>
|
||||||
|
|
||||||
|
namespace chatterino::qmagicenum::detail {
|
||||||
|
|
||||||
|
template <bool, typename R>
|
||||||
|
struct EnableIfEnum {
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
struct EnableIfEnum<true, R> {
|
||||||
|
using type = R;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>,
|
||||||
|
typename D = std::decay_t<T>>
|
||||||
|
using enable_if_t = typename EnableIfEnum<
|
||||||
|
std::is_enum_v<D> &&
|
||||||
|
std::is_invocable_r_v<bool, BinaryPredicate, QChar, QChar>,
|
||||||
|
R>::type;
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
consteval QStringView fromArray(const std::array<char16_t, N> &arr)
|
||||||
|
{
|
||||||
|
return QStringView{arr.data(), static_cast<QStringView::size_type>(N - 1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the latin1 subset may be used right now, since it's easily convertible
|
||||||
|
template <std::size_t N>
|
||||||
|
consteval bool isLatin1(std::string_view maybe)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
if (maybe[i] < 0x20 || maybe[i] > 0x7e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BinaryPredicate>
|
||||||
|
inline constexpr bool eq(
|
||||||
|
QStringView a, QStringView b,
|
||||||
|
[[maybe_unused]] BinaryPredicate &&
|
||||||
|
p) noexcept(magic_enum::detail::is_nothrow_invocable<BinaryPredicate>())
|
||||||
|
{
|
||||||
|
// Note: operator== isn't constexpr
|
||||||
|
if (a.size() != b.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (QStringView::size_type i = 0; i < a.size(); i++)
|
||||||
|
{
|
||||||
|
if (!p(a[i], b[i]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename C, typename E, E V>
|
||||||
|
consteval auto enumNameStorage()
|
||||||
|
{
|
||||||
|
constexpr auto utf8 = magic_enum::enum_name<V>();
|
||||||
|
|
||||||
|
static_assert(isLatin1<utf8.size()>(utf8),
|
||||||
|
"Can't convert non-latin1 UTF8 to UTF16");
|
||||||
|
|
||||||
|
std::array<C, utf8.size() + 1> storage;
|
||||||
|
for (std::size_t i = 0; i < utf8.size(); i++)
|
||||||
|
{
|
||||||
|
storage[i] = static_cast<C>(utf8[i]);
|
||||||
|
}
|
||||||
|
storage[utf8.size()] = 0;
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, E V>
|
||||||
|
inline constexpr auto ENUM_NAME_STORAGE = enumNameStorage<char16_t, E, V>();
|
||||||
|
|
||||||
|
template <typename E, magic_enum::detail::enum_subtype S, std::size_t... I>
|
||||||
|
consteval auto namesStorage(std::index_sequence<I...> /*unused*/)
|
||||||
|
{
|
||||||
|
return std::array<QStringView, sizeof...(I)>{{detail::fromArray(
|
||||||
|
ENUM_NAME_STORAGE<E, magic_enum::enum_values<E, S>()[I]>)...}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E,
|
||||||
|
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
||||||
|
inline constexpr auto NAMES_STORAGE = namesStorage<E, S>(
|
||||||
|
std::make_index_sequence<magic_enum::enum_count<E, S>()>{});
|
||||||
|
|
||||||
|
template <typename E, magic_enum::detail::enum_subtype S,
|
||||||
|
typename D = std::decay_t<E>>
|
||||||
|
using NamesStorage = decltype((NAMES_STORAGE<D, S>));
|
||||||
|
|
||||||
|
template <typename Op = std::equal_to<>>
|
||||||
|
class CaseInsensitive
|
||||||
|
{
|
||||||
|
static constexpr QChar toLower(QChar c) noexcept
|
||||||
|
{
|
||||||
|
return (c >= u'A' && c <= u'Z')
|
||||||
|
? QChar(c.unicode() + static_cast<char16_t>(u'a' - u'A'))
|
||||||
|
: c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr std::enable_if_t<std::is_same_v<std::decay_t<L>, QChar> &&
|
||||||
|
std::is_same_v<std::decay_t<R>, QChar>,
|
||||||
|
bool>
|
||||||
|
operator()(L lhs, R rhs) const noexcept
|
||||||
|
{
|
||||||
|
return Op{}(toLower(lhs), toLower(rhs));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino::qmagicenum::detail
|
||||||
|
|
||||||
|
namespace chatterino::qmagicenum {
|
||||||
|
|
||||||
|
/// @brief Get the name of an enum value
|
||||||
|
///
|
||||||
|
/// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
|
||||||
|
///
|
||||||
|
/// @tparam V The enum value
|
||||||
|
/// @returns The name as a string view
|
||||||
|
template <auto V>
|
||||||
|
[[nodiscard]] consteval detail::enable_if_t<decltype(V), QStringView>
|
||||||
|
enumName() noexcept
|
||||||
|
{
|
||||||
|
return QStringView{
|
||||||
|
detail::fromArray(detail::ENUM_NAME_STORAGE<decltype(V), V>)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the name of an enum value
|
||||||
|
///
|
||||||
|
/// @param value The enum value
|
||||||
|
/// @returns The name as a string view. If @a value does not have name or the
|
||||||
|
/// value is out of range an empty string is returned.
|
||||||
|
template <typename E,
|
||||||
|
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
||||||
|
[[nodiscard]] constexpr detail::enable_if_t<E, QStringView> enumName(
|
||||||
|
E value) noexcept
|
||||||
|
{
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
if (const auto i = magic_enum::enum_index<D, S>(value))
|
||||||
|
{
|
||||||
|
return detail::NAMES_STORAGE<D, S>[*i];
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets a static QString from @a view.
|
||||||
|
///
|
||||||
|
/// @pre @a view must be a static string view (i.e. it must be valid throughout
|
||||||
|
/// the entire duration of the program).
|
||||||
|
///
|
||||||
|
/// @param view The view to turn into a static string
|
||||||
|
/// @returns Qt6: A static string (never gets freed), Qt5: regular string
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
[[nodiscard]] inline QString staticString(QStringView view) noexcept
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
return QString(QStringPrivate(nullptr, const_cast<char16_t *>(view.utf16()),
|
||||||
|
view.size()));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
[[nodiscard]] inline QString staticString(QStringView view)
|
||||||
|
{
|
||||||
|
return view.toString();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @brief Get the name of an enum value
|
||||||
|
///
|
||||||
|
/// This version is much lighter on the compile times and is not restricted to
|
||||||
|
/// the enum_range limitation.
|
||||||
|
///
|
||||||
|
/// @tparam V The enum value
|
||||||
|
/// @returns The name as a string. The returned string is static.
|
||||||
|
template <auto V>
|
||||||
|
[[nodiscard]] inline detail::enable_if_t<decltype(V), QString>
|
||||||
|
enumNameString() noexcept
|
||||||
|
{
|
||||||
|
return staticString(enumName<V>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the name of an enum value
|
||||||
|
///
|
||||||
|
/// This version is much lighter on the compile times and is not restricted to
|
||||||
|
/// the enum_range limitation.
|
||||||
|
///
|
||||||
|
/// @tparam V The enum value
|
||||||
|
/// @returns The name as a string. If @a value does not have name or the
|
||||||
|
/// value is out of range an empty string is returned.
|
||||||
|
/// The returned string is static.
|
||||||
|
template <typename E,
|
||||||
|
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
||||||
|
[[nodiscard]] inline detail::enable_if_t<E, QString> enumNameString(
|
||||||
|
E value) noexcept
|
||||||
|
{
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
return staticString(enumName<D, S>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the enum value from a name
|
||||||
|
///
|
||||||
|
/// @tparam E The enum type to parse the @a name as
|
||||||
|
/// @param name The name of the enum value to parse
|
||||||
|
/// @param p A predicate to compare characters of a string
|
||||||
|
/// (defaults to std::equal_to)
|
||||||
|
/// @returns A `std::optional` of the parsed value. If no value was parsed,
|
||||||
|
/// `std::nullopt` is returned.
|
||||||
|
template <typename E,
|
||||||
|
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>,
|
||||||
|
typename BinaryPredicate = std::equal_to<>>
|
||||||
|
[[nodiscard]] constexpr detail::enable_if_t<E, std::optional<std::decay_t<E>>,
|
||||||
|
BinaryPredicate>
|
||||||
|
enumCast(QStringView name,
|
||||||
|
[[maybe_unused]] BinaryPredicate p =
|
||||||
|
{}) noexcept(magic_enum::detail::
|
||||||
|
is_nothrow_invocable<BinaryPredicate>())
|
||||||
|
{
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
if constexpr (magic_enum::enum_count<D, S>() == 0)
|
||||||
|
{
|
||||||
|
static_cast<void>(name);
|
||||||
|
return std::nullopt; // Empty enum.
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); i++)
|
||||||
|
{
|
||||||
|
if (detail::eq(name, detail::NAMES_STORAGE<D, S>[i], p))
|
||||||
|
{
|
||||||
|
return magic_enum::enum_value<D, S>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt; // Invalid value or out of range.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Constructs a name from the @a flags
|
||||||
|
///
|
||||||
|
/// @param flags The combined flags to construct the name from
|
||||||
|
/// @param sep A separator between each flag (defaults to u'|')
|
||||||
|
/// @returns A string containing all names separated by @a sep. If any flag in
|
||||||
|
/// @a flags is out of rage or does not have a name, an empty string
|
||||||
|
/// is returned.
|
||||||
|
template <typename E>
|
||||||
|
[[nodiscard]] inline detail::enable_if_t<E, QString> enumFlagsName(
|
||||||
|
E flags, char16_t sep = u'|')
|
||||||
|
{
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
using U = std::underlying_type_t<D>;
|
||||||
|
constexpr auto S = magic_enum::detail::enum_subtype::flags; // NOLINT
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
auto checkValue = U{0};
|
||||||
|
for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); ++i)
|
||||||
|
{
|
||||||
|
const auto v = static_cast<U>(magic_enum::enum_value<D, S>(i));
|
||||||
|
if ((static_cast<U>(flags) & v) != 0)
|
||||||
|
{
|
||||||
|
const auto n = detail::NAMES_STORAGE<D, S>[i];
|
||||||
|
if (!n.empty())
|
||||||
|
{
|
||||||
|
checkValue |= v;
|
||||||
|
if (!name.isEmpty())
|
||||||
|
{
|
||||||
|
name.append(sep);
|
||||||
|
}
|
||||||
|
name.append(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {}; // Value out of range.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkValue != 0 && checkValue == static_cast<U>(flags))
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return {}; // Invalid value or out of range.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get the names of all values from @a E.
|
||||||
|
///
|
||||||
|
/// @tparam E The enum type
|
||||||
|
/// @returns A `std::array` of all names (`QStringView`s)
|
||||||
|
template <typename E,
|
||||||
|
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
||||||
|
[[nodiscard]] constexpr auto enumNames() noexcept
|
||||||
|
-> detail::enable_if_t<E, detail::NamesStorage<E, S>>
|
||||||
|
{
|
||||||
|
return detail::NAMES_STORAGE<std::decay_t<E>, S>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows you to write qmagicenum::enumCast<foo>("bar", qmagicenum::CASE_INSENSITIVE)
|
||||||
|
inline constexpr auto CASE_INSENSITIVE = detail::CaseInsensitive<>{};
|
||||||
|
|
||||||
|
} // namespace chatterino::qmagicenum
|
|
@ -33,6 +33,7 @@
|
||||||
#include "util/DistanceBetweenPoints.hpp"
|
#include "util/DistanceBetweenPoints.hpp"
|
||||||
#include "util/Helpers.hpp"
|
#include "util/Helpers.hpp"
|
||||||
#include "util/IncognitoBrowser.hpp"
|
#include "util/IncognitoBrowser.hpp"
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
#include "util/Twitch.hpp"
|
#include "util/Twitch.hpp"
|
||||||
#include "widgets/dialogs/ReplyThreadPopup.hpp"
|
#include "widgets/dialogs/ReplyThreadPopup.hpp"
|
||||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||||
|
@ -266,8 +267,7 @@ void addHiddenContextMenuItems(QMenu *menu,
|
||||||
jsonObject["id"] = message->id;
|
jsonObject["id"] = message->id;
|
||||||
jsonObject["searchText"] = message->searchText;
|
jsonObject["searchText"] = message->searchText;
|
||||||
jsonObject["messageText"] = message->messageText;
|
jsonObject["messageText"] = message->messageText;
|
||||||
jsonObject["flags"] = QString::fromStdString(
|
jsonObject["flags"] = qmagicenum::enumFlagsName(message->flags.value());
|
||||||
magic_enum::enum_flags_name(message->flags.value()));
|
|
||||||
|
|
||||||
jsonDocument.setObject(jsonObject);
|
jsonDocument.setObject(jsonObject);
|
||||||
|
|
||||||
|
|
|
@ -1243,7 +1243,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||||
helixTimegateModerators->minimumSizeHint().width());
|
helixTimegateModerators->minimumSizeHint().width());
|
||||||
|
|
||||||
layout.addDropdownEnumClass<ChatSendProtocol>(
|
layout.addDropdownEnumClass<ChatSendProtocol>(
|
||||||
"Chat send protocol", magic_enum::enum_names<ChatSendProtocol>(),
|
"Chat send protocol", qmagicenum::enumNames<ChatSendProtocol>(),
|
||||||
s.chatSendProtocol,
|
s.chatSendProtocol,
|
||||||
"'Helix' will use Twitch's Helix API to send message. 'IRC' will use "
|
"'Helix' will use Twitch's Helix API to send message. 'IRC' will use "
|
||||||
"IRC to send messages.",
|
"IRC to send messages.",
|
||||||
|
@ -1256,7 +1256,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
||||||
|
|
||||||
auto *soundBackend = layout.addDropdownEnumClass<SoundBackend>(
|
auto *soundBackend = layout.addDropdownEnumClass<SoundBackend>(
|
||||||
"Sound backend (requires restart)",
|
"Sound backend (requires restart)",
|
||||||
magic_enum::enum_names<SoundBackend>(), s.soundBackend,
|
qmagicenum::enumNames<SoundBackend>(), s.soundBackend,
|
||||||
"Change this only if you're noticing issues with sound playback on "
|
"Change this only if you're noticing issues with sound playback on "
|
||||||
"your system",
|
"your system",
|
||||||
{});
|
{});
|
||||||
|
|
|
@ -276,7 +276,7 @@ public:
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
ComboBox *addDropdownEnumClass(const QString &text,
|
ComboBox *addDropdownEnumClass(const QString &text,
|
||||||
const std::array<std::string_view, N> &items,
|
const std::array<QStringView, N> &items,
|
||||||
EnumStringSetting<T> &setting,
|
EnumStringSetting<T> &setting,
|
||||||
QString toolTipText,
|
QString toolTipText,
|
||||||
const QString &defaultValueText)
|
const QString &defaultValueText)
|
||||||
|
@ -285,7 +285,7 @@ public:
|
||||||
|
|
||||||
for (const auto &item : items)
|
for (const auto &item : items)
|
||||||
{
|
{
|
||||||
combo->addItem(QString::fromStdString(std::string(item)));
|
combo->addItem(item.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultValueText.isEmpty())
|
if (!defaultValueText.isEmpty())
|
||||||
|
@ -296,8 +296,7 @@ public:
|
||||||
setting.connect(
|
setting.connect(
|
||||||
[&setting, combo](const QString &value) {
|
[&setting, combo](const QString &value) {
|
||||||
auto enumValue =
|
auto enumValue =
|
||||||
magic_enum::enum_cast<T>(value.toStdString(),
|
qmagicenum::enumCast<T>(value, qmagicenum::CASE_INSENSITIVE)
|
||||||
magic_enum::case_insensitive)
|
|
||||||
.value_or(setting.defaultValue);
|
.value_or(setting.defaultValue);
|
||||||
|
|
||||||
auto i = magic_enum::enum_integer(enumValue);
|
auto i = magic_enum::enum_integer(enumValue);
|
||||||
|
|
|
@ -40,6 +40,7 @@ set(test_SOURCES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/SplitInput.cpp
|
${CMAKE_CURRENT_LIST_DIR}/src/SplitInput.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/LinkInfo.cpp
|
${CMAKE_CURRENT_LIST_DIR}/src/LinkInfo.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/MessageLayout.cpp
|
${CMAKE_CURRENT_LIST_DIR}/src/MessageLayout.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/QMagicEnum.cpp
|
||||||
# Add your new file above this line!
|
# Add your new file above this line!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
198
tests/src/QMagicEnum.cpp
Normal file
198
tests/src/QMagicEnum.cpp
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#include "util/QMagicEnum.hpp"
|
||||||
|
|
||||||
|
#include "common/FlagsEnum.hpp"
|
||||||
|
#include "common/Literals.hpp"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
using namespace chatterino;
|
||||||
|
using namespace literals;
|
||||||
|
|
||||||
|
using qmagicenum::enumCast;
|
||||||
|
using qmagicenum::enumFlagsName;
|
||||||
|
using qmagicenum::enumName;
|
||||||
|
using qmagicenum::enumNames;
|
||||||
|
using qmagicenum::enumNameString;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum class MyEnum {
|
||||||
|
Foo,
|
||||||
|
Bar,
|
||||||
|
Baz,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MyFlag {
|
||||||
|
None = 0,
|
||||||
|
One = 1,
|
||||||
|
Two = 2,
|
||||||
|
Four = 4,
|
||||||
|
Eight = 8,
|
||||||
|
};
|
||||||
|
using MyFlags = chatterino::FlagsEnum<MyFlag>;
|
||||||
|
|
||||||
|
enum class MyCustom {
|
||||||
|
Default = 1,
|
||||||
|
First = 4,
|
||||||
|
Second = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MyOpen {
|
||||||
|
OpenOne = 11,
|
||||||
|
OpenTwo = 12,
|
||||||
|
OpenThree = 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
consteval bool eq(QStringView a, QStringView b)
|
||||||
|
{
|
||||||
|
return qmagicenum::detail::eq(a, b, std::equal_to<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
consteval bool checkConst(E value, QStringView expectedName)
|
||||||
|
{
|
||||||
|
return eq(enumName(value), expectedName) &&
|
||||||
|
enumCast<E>(expectedName) == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
consteval bool checkInsensitive(E value, QStringView possible)
|
||||||
|
{
|
||||||
|
return enumCast<E>(possible, qmagicenum::CASE_INSENSITIVE) == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename E, std::size_t N = enumNames<E>().size()>
|
||||||
|
consteval bool checkValues(std::array<QStringView, N> values)
|
||||||
|
{
|
||||||
|
constexpr auto got = enumNames<E>();
|
||||||
|
if (got.size() != N)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
if (!eq(got.at(i), values.at(i)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct magic_enum::customize::enum_range<MyFlag> {
|
||||||
|
static constexpr bool is_flags = true; // NOLINT
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr magic_enum::customize::customize_t
|
||||||
|
magic_enum::customize::enum_name<MyCustom>(MyCustom value) noexcept
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case MyCustom::First:
|
||||||
|
return "myfirst";
|
||||||
|
case MyCustom::Second:
|
||||||
|
return "mysecond.*";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return default_tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, basic)
|
||||||
|
{
|
||||||
|
static_assert(eq(enumName<MyEnum::Foo>(), u"Foo"));
|
||||||
|
static_assert(eq(enumName<MyEnum::Bar>(), u"Bar"));
|
||||||
|
static_assert(eq(enumName<MyEnum::Baz>(), u"Baz"));
|
||||||
|
static_assert(checkConst(MyEnum::Foo, u"Foo"));
|
||||||
|
static_assert(checkConst(MyEnum::Bar, u"Bar"));
|
||||||
|
static_assert(checkConst(MyEnum::Baz, u"Baz"));
|
||||||
|
static_assert(eq(enumName(static_cast<MyEnum>(16)), u""));
|
||||||
|
static_assert(checkValues<MyEnum>({u"Foo", u"Bar", u"Baz"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, flags)
|
||||||
|
{
|
||||||
|
static_assert(eq(enumName<MyFlag::None>(), u"None"));
|
||||||
|
static_assert(eq(enumName<MyFlag::One>(), u"One"));
|
||||||
|
static_assert(eq(enumName<MyFlag::Two>(), u"Two"));
|
||||||
|
static_assert(eq(enumName<MyFlag::Four>(), u"Four"));
|
||||||
|
static_assert(eq(enumName<MyFlag::Eight>(), u"Eight"));
|
||||||
|
|
||||||
|
static_assert(!magic_enum::enum_index<MyFlag>(MyFlag::None).has_value());
|
||||||
|
static_assert(eq(enumName(MyFlag::None), u""));
|
||||||
|
|
||||||
|
static_assert(checkConst(MyFlag::One, u"One"));
|
||||||
|
static_assert(checkConst(MyFlag::Two, u"Two"));
|
||||||
|
static_assert(checkConst(MyFlag::Four, u"Four"));
|
||||||
|
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
||||||
|
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
||||||
|
static_assert(eq(enumName(static_cast<MyFlag>(16)), u""));
|
||||||
|
static_assert(checkValues<MyFlag>({u"One", u"Two", u"Four", u"Eight"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, enumNameString)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(enumNameString<MyEnum::Baz>(), u"Baz");
|
||||||
|
|
||||||
|
ASSERT_EQ(enumNameString<MyFlag::None>(), u"None");
|
||||||
|
ASSERT_EQ(enumNameString<MyFlag::Four>(), u"Four");
|
||||||
|
|
||||||
|
ASSERT_EQ(enumNameString(MyEnum::Bar), u"Bar");
|
||||||
|
ASSERT_EQ(enumNameString(MyFlag::None), u"");
|
||||||
|
ASSERT_EQ(enumNameString(MyFlag::One), u"One");
|
||||||
|
ASSERT_EQ(enumNameString(MyCustom::Second), u"mysecond.*");
|
||||||
|
ASSERT_EQ(enumNameString(OpenTwo), u"OpenTwo");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, enumFlagsName)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(enumFlagsName(MyFlag::Eight), u"Eight"_s);
|
||||||
|
ASSERT_EQ(enumFlagsName(MyFlag::None), u""_s);
|
||||||
|
ASSERT_EQ(enumFlagsName(MyFlags{MyFlag::Eight, MyFlag::Four}.value(), u'+'),
|
||||||
|
u"Four+Eight"_s);
|
||||||
|
ASSERT_EQ(enumFlagsName(
|
||||||
|
MyFlags{MyFlag::Eight, MyFlag::One, MyFlag::Two, MyFlag::Four}
|
||||||
|
.value()),
|
||||||
|
u"One|Two|Four|Eight"_s);
|
||||||
|
ASSERT_EQ(
|
||||||
|
enumFlagsName(MyFlags{MyFlag::One, static_cast<MyFlag>(16)}.value()),
|
||||||
|
u""_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, renamed)
|
||||||
|
{
|
||||||
|
static_assert(eq(enumName<MyCustom::Default>(), u"Default"));
|
||||||
|
static_assert(eq(enumName<MyCustom::First>(), u"myfirst"));
|
||||||
|
static_assert(eq(enumName<MyCustom::Second>(), u"mysecond.*"));
|
||||||
|
static_assert(checkConst(MyCustom::Default, u"Default"));
|
||||||
|
static_assert(checkConst(MyCustom::First, u"myfirst"));
|
||||||
|
static_assert(checkConst(MyCustom::Second, u"mysecond.*"));
|
||||||
|
static_assert(eq(enumName(static_cast<MyCustom>(16)), u""));
|
||||||
|
static_assert(
|
||||||
|
checkValues<MyCustom>({u"Default", u"myfirst", u"mysecond.*"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, open)
|
||||||
|
{
|
||||||
|
static_assert(eq(enumName<OpenOne>(), u"OpenOne"));
|
||||||
|
static_assert(eq(enumName<OpenTwo>(), u"OpenTwo"));
|
||||||
|
static_assert(eq(enumName<OpenThree>(), u"OpenThree"));
|
||||||
|
static_assert(checkConst(OpenOne, u"OpenOne"));
|
||||||
|
static_assert(checkConst(OpenTwo, u"OpenTwo"));
|
||||||
|
static_assert(checkConst(OpenThree, u"OpenThree"));
|
||||||
|
static_assert(eq(enumName(static_cast<MyOpen>(16)), u""));
|
||||||
|
static_assert(checkValues<MyOpen>({u"OpenOne", u"OpenTwo", u"OpenThree"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(QMagicEnum, caseInsensitive)
|
||||||
|
{
|
||||||
|
static_assert(checkInsensitive(MyEnum::Foo, u"foo"));
|
||||||
|
static_assert(checkInsensitive(MyEnum::Bar, u"BAR"));
|
||||||
|
static_assert(checkInsensitive(MyFlag::Four, u"fOUR"));
|
||||||
|
static_assert(checkInsensitive(MyCustom::Second, u"MySecond.*"));
|
||||||
|
static_assert(checkInsensitive(OpenOne, u"openone"));
|
||||||
|
}
|
Loading…
Reference in a new issue