mirror of
https://github.com/hyprwm/hyprlang.git
synced 2024-11-16 18:25:57 +01:00
core: add custom data types
This commit is contained in:
parent
8d538588ff
commit
a081d90b19
6 changed files with 217 additions and 83 deletions
|
@ -9,6 +9,8 @@
|
|||
#include <fstream>
|
||||
|
||||
class CConfigImpl;
|
||||
struct SConfigDefaultValue;
|
||||
struct SSpecialCategory;
|
||||
|
||||
namespace Hyprlang {
|
||||
|
||||
|
@ -66,8 +68,30 @@ namespace Hyprlang {
|
|||
|
||||
/* typedefs */
|
||||
typedef CParseResult (*PCONFIGHANDLERFUNC)(const char* COMMAND, const char* VALUE);
|
||||
typedef CParseResult (*PCONFIGCUSTOMVALUEHANDLERFUNC)(const char* VALUE, void** data);
|
||||
typedef void (*PCONFIGCUSTOMVALUEDESTRUCTOR)(void** data);
|
||||
|
||||
/* Container for a custom config value type
|
||||
When creating, pass your handler.
|
||||
Handler will receive a void** that points to a void* that you can set to your own
|
||||
thing. Pass a dtor to free whatever you allocated when the custom value type is being released.
|
||||
data may always be pointing to a nullptr.
|
||||
*/
|
||||
class CConfigCustomValueType {
|
||||
public:
|
||||
CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC handler_, PCONFIGCUSTOMVALUEDESTRUCTOR dtor_, const char* defaultValue);
|
||||
~CConfigCustomValueType();
|
||||
|
||||
private:
|
||||
PCONFIGCUSTOMVALUEHANDLERFUNC handler = nullptr;
|
||||
PCONFIGCUSTOMVALUEDESTRUCTOR dtor = nullptr;
|
||||
void* data = nullptr;
|
||||
std::string defaultVal = "";
|
||||
|
||||
friend class CConfigValue;
|
||||
friend class CConfig;
|
||||
};
|
||||
|
||||
struct SConfigValueImpl;
|
||||
/* Container for a config value */
|
||||
class CConfigValue {
|
||||
public:
|
||||
|
@ -76,9 +100,11 @@ namespace Hyprlang {
|
|||
CConfigValue(const float value);
|
||||
CConfigValue(const char* value);
|
||||
CConfigValue(const SVector2D value);
|
||||
CConfigValue(const CConfigValue&);
|
||||
CConfigValue(CConfigValue&&);
|
||||
void operator=(const CConfigValue&);
|
||||
CConfigValue(CConfigCustomValueType&& value);
|
||||
CConfigValue(const CConfigValue&) = delete;
|
||||
CConfigValue(CConfigValue&&) = delete;
|
||||
CConfigValue(const CConfigValue&&) = delete;
|
||||
CConfigValue(CConfigValue&) = delete;
|
||||
~CConfigValue();
|
||||
|
||||
void* dataPtr() const;
|
||||
|
@ -89,21 +115,26 @@ namespace Hyprlang {
|
|||
case CONFIGDATATYPE_FLOAT: return std::any(*reinterpret_cast<float*>(m_pData));
|
||||
case CONFIGDATATYPE_STR: return std::any(reinterpret_cast<const char*>(m_pData));
|
||||
case CONFIGDATATYPE_VEC2: return std::any(*reinterpret_cast<SVector2D*>(m_pData));
|
||||
case CONFIGDATATYPE_CUSTOM: return std::any(reinterpret_cast<CConfigCustomValueType*>(m_pData)->data);
|
||||
default: throw;
|
||||
}
|
||||
return {}; // unreachable
|
||||
}
|
||||
|
||||
private:
|
||||
// remember to also edit config.hpp if editing
|
||||
enum eDataType {
|
||||
CONFIGDATATYPE_EMPTY,
|
||||
CONFIGDATATYPE_INT,
|
||||
CONFIGDATATYPE_FLOAT,
|
||||
CONFIGDATATYPE_STR,
|
||||
CONFIGDATATYPE_VEC2,
|
||||
CONFIGDATATYPE_CUSTOM,
|
||||
};
|
||||
eDataType m_eType = eDataType::CONFIGDATATYPE_EMPTY;
|
||||
void* m_pData = nullptr;
|
||||
void defaultFrom(SConfigDefaultValue& ref);
|
||||
void setFrom(std::any value);
|
||||
|
||||
friend class CConfig;
|
||||
};
|
||||
|
@ -117,7 +148,7 @@ namespace Hyprlang {
|
|||
/* Add a config value, for example myCategory:myValue.
|
||||
This has to be done before commence()
|
||||
Value provided becomes default */
|
||||
void addConfigValue(const char* name, const CConfigValue value);
|
||||
void addConfigValue(const char* name, const CConfigValue& value);
|
||||
|
||||
/* Register a handler. Can be called anytime, though not recommended
|
||||
to do this dynamically */
|
||||
|
@ -181,6 +212,7 @@ namespace Hyprlang {
|
|||
CParseResult configSetValueSafe(const std::string& command, const std::string& value);
|
||||
CParseResult parseVariable(const std::string& lhs, const std::string& rhs, bool dynamic = false);
|
||||
void clearState();
|
||||
void applyDefaultsToCat(SSpecialCategory& cat);
|
||||
};
|
||||
};
|
||||
#endif
|
155
src/common.cpp
155
src/common.cpp
|
@ -1,4 +1,5 @@
|
|||
#include "public.hpp"
|
||||
#include "config.hpp"
|
||||
#include <string.h>
|
||||
|
||||
using namespace Hyprlang;
|
||||
|
@ -16,6 +17,9 @@ void CParseResult::setError(const char* err) {
|
|||
}
|
||||
|
||||
CConfigValue::~CConfigValue() {
|
||||
if (m_eType == CONFIGDATATYPE_CUSTOM)
|
||||
reinterpret_cast<CConfigCustomValueType*>(m_pData)->dtor(&reinterpret_cast<CConfigCustomValueType*>(m_pData)->data);
|
||||
|
||||
if (m_pData)
|
||||
free(m_pData);
|
||||
}
|
||||
|
@ -44,65 +48,10 @@ CConfigValue::CConfigValue(const char* value) {
|
|||
m_eType = CONFIGDATATYPE_STR;
|
||||
}
|
||||
|
||||
CConfigValue::CConfigValue(const CConfigValue& ref) {
|
||||
m_eType = ref.m_eType;
|
||||
switch (ref.m_eType) {
|
||||
case eDataType::CONFIGDATATYPE_INT: {
|
||||
m_pData = calloc(1, sizeof(int64_t));
|
||||
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_FLOAT: {
|
||||
m_pData = calloc(1, sizeof(float));
|
||||
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_VEC2: {
|
||||
m_pData = calloc(1, sizeof(SVector2D));
|
||||
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_STR: {
|
||||
auto str = std::any_cast<const char*>(ref.getValue());
|
||||
m_pData = calloc(1, strlen(str) + 1);
|
||||
strncpy((char*)m_pData, str, strlen(str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigValue::operator=(const CConfigValue& ref) {
|
||||
m_eType = ref.m_eType;
|
||||
switch (ref.m_eType) {
|
||||
case eDataType::CONFIGDATATYPE_INT: {
|
||||
m_pData = calloc(1, sizeof(int64_t));
|
||||
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_FLOAT: {
|
||||
m_pData = calloc(1, sizeof(float));
|
||||
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_VEC2: {
|
||||
m_pData = calloc(1, sizeof(SVector2D));
|
||||
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.getValue());
|
||||
break;
|
||||
}
|
||||
case eDataType::CONFIGDATATYPE_STR: {
|
||||
auto str = std::any_cast<const char*>(ref.getValue());
|
||||
m_pData = calloc(1, strlen(str) + 1);
|
||||
strncpy((char*)m_pData, str, strlen(str));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CConfigValue::CConfigValue(CConfigValue&& ref) {
|
||||
m_pData = ref.dataPtr();
|
||||
m_eType = ref.m_eType;
|
||||
ref.m_eType = eDataType::CONFIGDATATYPE_EMPTY;
|
||||
ref.m_pData = nullptr;
|
||||
CConfigValue::CConfigValue(CConfigCustomValueType&& value) {
|
||||
m_pData = calloc(1, sizeof(CConfigCustomValueType));
|
||||
new (m_pData) CConfigCustomValueType(value);
|
||||
m_eType = CONFIGDATATYPE_CUSTOM;
|
||||
}
|
||||
|
||||
CConfigValue::CConfigValue() {
|
||||
|
@ -112,3 +61,91 @@ CConfigValue::CConfigValue() {
|
|||
void* CConfigValue::dataPtr() const {
|
||||
return m_pData;
|
||||
}
|
||||
|
||||
CConfigCustomValueType::CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC handler_, PCONFIGCUSTOMVALUEDESTRUCTOR dtor_, const char* def) {
|
||||
handler = handler_;
|
||||
dtor = dtor_;
|
||||
defaultVal = def;
|
||||
}
|
||||
|
||||
CConfigCustomValueType::~CConfigCustomValueType() {
|
||||
dtor(&data);
|
||||
}
|
||||
|
||||
void CConfigValue::defaultFrom(SConfigDefaultValue& ref) {
|
||||
m_eType = (CConfigValue::eDataType)ref.type;
|
||||
switch (m_eType) {
|
||||
case CONFIGDATATYPE_FLOAT: {
|
||||
if (!m_pData)
|
||||
m_pData = calloc(1, sizeof(float));
|
||||
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.data);
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_INT: {
|
||||
if (!m_pData)
|
||||
m_pData = calloc(1, sizeof(int64_t));
|
||||
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.data);
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_STR: {
|
||||
if (!m_pData)
|
||||
free(m_pData);
|
||||
std::string str = std::any_cast<std::string>(ref.data);
|
||||
m_pData = calloc(1, str.length() + 1);
|
||||
strncpy((char*)m_pData, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_VEC2: {
|
||||
if (!m_pData)
|
||||
m_pData = calloc(1, sizeof(SVector2D));
|
||||
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.data);
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_CUSTOM: {
|
||||
if (!m_pData)
|
||||
m_pData = calloc(1, sizeof(CConfigCustomValueType));
|
||||
CConfigCustomValueType* type = reinterpret_cast<CConfigCustomValueType*>(m_pData);
|
||||
type->handler = ref.handler;
|
||||
type->dtor = ref.dtor;
|
||||
type->handler(std::any_cast<std::string>(ref.data).c_str(), &type->data);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw "bad defaultFrom type";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigValue::setFrom(std::any value) {
|
||||
switch (m_eType) {
|
||||
case CONFIGDATATYPE_FLOAT: {
|
||||
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(value);
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_INT: {
|
||||
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(value);
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_STR: {
|
||||
free(m_pData);
|
||||
std::string str = std::any_cast<std::string>(value);
|
||||
m_pData = calloc(1, str.length() + 1);
|
||||
strncpy((char*)m_pData, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case CONFIGDATATYPE_VEC2: {
|
||||
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(value);
|
||||
break;
|
||||
}
|
||||
// case CONFIGDATATYPE_CUSTOM: {
|
||||
// CConfigCustomValueType* type = reinterpret_cast<CConfigCustomValueType*>(m_pData);
|
||||
// type->handler = ref.handler;
|
||||
// type->dtor = ref.dtor;
|
||||
// type->handler(std::any_cast<std::string>(ref.data).c_str(), &type->data);
|
||||
// break;
|
||||
// }
|
||||
default: {
|
||||
throw "bad defaultFrom type";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,11 +52,19 @@ CConfig::~CConfig() {
|
|||
delete impl;
|
||||
}
|
||||
|
||||
void CConfig::addConfigValue(const char* name, const CConfigValue value) {
|
||||
void CConfig::addConfigValue(const char* name, const CConfigValue& value) {
|
||||
if (m_bCommenced)
|
||||
throw "Cannot addConfigValue after commence()";
|
||||
|
||||
impl->defaultValues[std::string{name}] = value;
|
||||
if ((eDataType)value.m_eType != CONFIGDATATYPE_CUSTOM && (eDataType)value.m_eType != CONFIGDATATYPE_STR)
|
||||
impl->defaultValues.emplace(name, SConfigDefaultValue{value.getValue(), (eDataType)value.m_eType});
|
||||
else if ((eDataType)value.m_eType == CONFIGDATATYPE_STR)
|
||||
impl->defaultValues.emplace(name, SConfigDefaultValue{std::string{std::any_cast<const char*>(value.getValue())}, (eDataType)value.m_eType});
|
||||
else
|
||||
impl->defaultValues.emplace(name,
|
||||
SConfigDefaultValue{reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->defaultVal, (eDataType)value.m_eType,
|
||||
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->handler,
|
||||
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->dtor});
|
||||
}
|
||||
|
||||
void CConfig::addSpecialConfigValue(const char* cat, const char* name, const CConfigValue value) {
|
||||
|
@ -65,7 +73,15 @@ void CConfig::addSpecialConfigValue(const char* cat, const char* name, const CCo
|
|||
if (IT == impl->specialCategoryDescriptors.end())
|
||||
throw "No such category";
|
||||
|
||||
IT->get()->defaultValues[std::string{name}] = value;
|
||||
if ((eDataType)value.m_eType != CONFIGDATATYPE_CUSTOM && (eDataType)value.m_eType != CONFIGDATATYPE_STR)
|
||||
IT->get()->defaultValues.emplace(name, SConfigDefaultValue{value.getValue(), (eDataType)value.m_eType});
|
||||
else if ((eDataType)value.m_eType == CONFIGDATATYPE_STR)
|
||||
IT->get()->defaultValues.emplace(name, SConfigDefaultValue{std::string{std::any_cast<const char*>(value.getValue())}, (eDataType)value.m_eType});
|
||||
else
|
||||
IT->get()->defaultValues.emplace(name,
|
||||
SConfigDefaultValue{reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->defaultVal, (eDataType)value.m_eType,
|
||||
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->handler,
|
||||
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->dtor});
|
||||
}
|
||||
|
||||
void CConfig::addSpecialCategory(const char* name, SSpecialCategoryOptions options) {
|
||||
|
@ -85,16 +101,16 @@ void CConfig::addSpecialCategory(const char* name, SSpecialCategoryOptions optio
|
|||
}
|
||||
}
|
||||
|
||||
void SSpecialCategory::applyDefaults() {
|
||||
for (auto& [k, v] : descriptor->defaultValues) {
|
||||
values[k] = v;
|
||||
void CConfig::applyDefaultsToCat(SSpecialCategory& cat) {
|
||||
for (auto& [k, v] : cat.descriptor->defaultValues) {
|
||||
cat.values[k].defaultFrom(v);
|
||||
}
|
||||
}
|
||||
|
||||
void CConfig::commence() {
|
||||
m_bCommenced = true;
|
||||
for (auto& [k, v] : impl->defaultValues) {
|
||||
impl->values[k] = v;
|
||||
impl->values[k].defaultFrom(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,7 +256,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
PCAT->key = sc->key;
|
||||
addSpecialConfigValue(sc->name.c_str(), sc->key.c_str(), CConfigValue("0"));
|
||||
|
||||
PCAT->applyDefaults();
|
||||
applyDefaultsToCat(*PCAT);
|
||||
|
||||
VALUEIT = PCAT->values.find(valueName.substr(sc->name.length() + 1));
|
||||
|
||||
|
@ -267,7 +283,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
switch (VALUEIT->second.m_eType) {
|
||||
case CConfigValue::eDataType::CONFIGDATATYPE_INT: {
|
||||
try {
|
||||
VALUEIT->second = {configStringToInt(value)};
|
||||
VALUEIT->second.setFrom(configStringToInt(value));
|
||||
} catch (std::exception& e) {
|
||||
result.setError(std::format("failed parsing an int: {}", e.what()));
|
||||
return result;
|
||||
|
@ -276,7 +292,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
}
|
||||
case CConfigValue::eDataType::CONFIGDATATYPE_FLOAT: {
|
||||
try {
|
||||
VALUEIT->second = {std::stof(value)};
|
||||
VALUEIT->second.setFrom(std::stof(value));
|
||||
} catch (std::exception& e) {
|
||||
result.setError(std::format("failed parsing a float: {}", e.what()));
|
||||
return result;
|
||||
|
@ -294,7 +310,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
if (LHS.contains(" ") || RHS.contains(" "))
|
||||
throw std::runtime_error("too many args");
|
||||
|
||||
VALUEIT->second = {SVector2D{std::stof(LHS), std::stof(RHS)}};
|
||||
VALUEIT->second.setFrom(SVector2D{std::stof(LHS), std::stof(RHS)});
|
||||
} catch (std::exception& e) {
|
||||
result.setError(std::format("failed parsing a vec2: {}", e.what()));
|
||||
return result;
|
||||
|
@ -302,7 +318,11 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
|
|||
break;
|
||||
}
|
||||
case CConfigValue::eDataType::CONFIGDATATYPE_STR: {
|
||||
VALUEIT->second = {value.c_str()};
|
||||
VALUEIT->second.setFrom(value);
|
||||
break;
|
||||
}
|
||||
case CConfigValue::eDataType::CONFIGDATATYPE_CUSTOM: {
|
||||
reinterpret_cast<CConfigCustomValueType*>(VALUEIT->second.m_pData)->handler(value.c_str(), &reinterpret_cast<CConfigCustomValueType*>(VALUEIT->second.m_pData)->data);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -468,10 +488,10 @@ CParseResult CConfig::parse() {
|
|||
clearState();
|
||||
|
||||
for (auto& [k, v] : impl->defaultValues) {
|
||||
impl->values.at(k) = v;
|
||||
impl->values.at(k).defaultFrom(v);
|
||||
}
|
||||
for (auto& sc : impl->specialCategories) {
|
||||
sc->applyDefaults();
|
||||
applyDefaultsToCat(*sc);
|
||||
}
|
||||
|
||||
CParseResult fileParseResult = parseFile(impl->path);
|
||||
|
|
|
@ -16,11 +16,31 @@ struct SVariable {
|
|||
std::vector<std::string> linesContainingVar; // for dynamic updates
|
||||
};
|
||||
|
||||
// remember to also edit CConfigValue if editing
|
||||
enum eDataType {
|
||||
CONFIGDATATYPE_EMPTY,
|
||||
CONFIGDATATYPE_INT,
|
||||
CONFIGDATATYPE_FLOAT,
|
||||
CONFIGDATATYPE_STR,
|
||||
CONFIGDATATYPE_VEC2,
|
||||
CONFIGDATATYPE_CUSTOM,
|
||||
};
|
||||
|
||||
// CUSTOM is stored as STR!!
|
||||
struct SConfigDefaultValue {
|
||||
std::any data;
|
||||
eDataType type = CONFIGDATATYPE_EMPTY;
|
||||
|
||||
// this sucks but I have no better idea
|
||||
Hyprlang::PCONFIGCUSTOMVALUEHANDLERFUNC handler = nullptr;
|
||||
Hyprlang::PCONFIGCUSTOMVALUEDESTRUCTOR dtor = nullptr;
|
||||
};
|
||||
|
||||
struct SSpecialCategoryDescriptor {
|
||||
std::string name = "";
|
||||
std::string key = "";
|
||||
std::unordered_map<std::string, Hyprlang::CConfigValue> defaultValues;
|
||||
bool dontErrorOnMissing = false;
|
||||
std::string name = "";
|
||||
std::string key = "";
|
||||
std::unordered_map<std::string, SConfigDefaultValue> defaultValues;
|
||||
bool dontErrorOnMissing = false;
|
||||
};
|
||||
|
||||
struct SSpecialCategory {
|
||||
|
@ -38,7 +58,7 @@ class CConfigImpl {
|
|||
std::string path = "";
|
||||
|
||||
std::unordered_map<std::string, Hyprlang::CConfigValue> values;
|
||||
std::unordered_map<std::string, Hyprlang::CConfigValue> defaultValues;
|
||||
std::unordered_map<std::string, SConfigDefaultValue> defaultValues;
|
||||
std::vector<SHandler> handlers;
|
||||
std::vector<SVariable> variables;
|
||||
std::vector<SVariable> envVariables;
|
||||
|
|
|
@ -13,6 +13,8 @@ testEnv = $SHELL
|
|||
|
||||
source = ./colors.conf
|
||||
|
||||
customType = abc
|
||||
|
||||
testCategory {
|
||||
testValueInt = 123456
|
||||
testValueHex = 0xF
|
||||
|
|
|
@ -48,6 +48,24 @@ static Hyprlang::CParseResult handleSource(const char* COMMAND, const char* VALU
|
|||
return pConfig->parseFile(PATH);
|
||||
}
|
||||
|
||||
static Hyprlang::CParseResult handleCustomValueSet(const char* VALUE, void** data) {
|
||||
if (!*data)
|
||||
*data = calloc(1, sizeof(int64_t));
|
||||
std::string V = VALUE;
|
||||
if (V == "abc")
|
||||
*reinterpret_cast<int64_t*>(*data) = 1;
|
||||
else
|
||||
*reinterpret_cast<int64_t*>(*data) = 2;
|
||||
|
||||
Hyprlang::CParseResult result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void handleCustomValueDestroy(void** data) {
|
||||
if (*data)
|
||||
free(*data);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
int ret = 0;
|
||||
|
||||
|
@ -80,6 +98,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
config.addConfigValue("myColors:pink", 0L);
|
||||
config.addConfigValue("myColors:green", 0L);
|
||||
config.addConfigValue("myColors:random", 0L);
|
||||
config.addConfigValue("customType", {Hyprlang::CConfigCustomValueType{&handleCustomValueSet, &handleCustomValueDestroy, "def"}});
|
||||
|
||||
config.registerHandler(&handleDoABarrelRoll, "doABarrelRoll", {false});
|
||||
config.registerHandler(&handleFlagsTest, "flags", {true});
|
||||
|
@ -159,6 +178,10 @@ int main(int argc, char** argv, char** envp) {
|
|||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("myColors:green")), 0xFF14f014L);
|
||||
EXPECT(std::any_cast<int64_t>(config.getConfigValue("myColors:random")), 0xFFFF1337L);
|
||||
|
||||
// test custom type
|
||||
std::cout << " → Testing custom types\n";
|
||||
EXPECT(*reinterpret_cast<int64_t*>(std::any_cast<void*>(config.getConfigValue("customType"))), 1L);
|
||||
|
||||
} catch (const char* e) {
|
||||
std::cout << Colors::RED << "Error: " << Colors::RESET << e << "\n";
|
||||
return 1;
|
||||
|
|
Loading…
Reference in a new issue