Allow set enum as json value (#4363) (#4434)

* Allow set enum as json value (#4363)

* fix issue #4341
add testEnum
if you set enum as json value then it will be cast to int

* add behavour for enum into VarHolderImpl
add tests for enum classes with differnent underline integral types

* replace static_cast with convertTo* methods, they can chaeck types and
limits

* fix missing types for convert methods

* fix code style
add testEnumType to the VarTest.cpp, extract() works

* enh(VarHolder): replace ::value and ::type with shortcuts

---------

Co-authored-by: Alexander B <ale.bychuk@gmail.com>
This commit is contained in:
Aleksandar Fabijanic 2024-07-29 16:30:51 -05:00 committed by GitHub
parent 03444bdcea
commit 669be63134
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 591 additions and 1 deletions

View File

@ -417,6 +417,42 @@ protected:
to = static_cast<T>(from);
}
template <typename F, typename T, std::enable_if_t<std::is_signed_v<F> && std::is_signed_v<T> && (sizeof(F) <= sizeof(T))>* = nullptr>
void convertToSigned(const F& from, T& to) const
{
to = static_cast<T>(from);
}
template <typename F, typename T, std::enable_if_t<std::is_signed_v<F> && std::is_signed_v<T> && (sizeof(F) > sizeof(T))>* = nullptr>
void convertToSigned(const F& from, T& to) const
{
convertToSmaller(from, to);
}
template <typename F, typename T, std::enable_if_t<!std::is_signed_v<F> && std::is_signed_v<T>>* = nullptr>
void convertToSigned(const F& from, T& to) const
{
convertUnsignedToSigned(from, to);
}
template <typename F, typename T, std::enable_if_t<!std::is_signed_v<F> && !std::is_signed_v<T> && (sizeof(F) <= sizeof(T))>* = nullptr>
void convertToUnsigned(const F& from, T& to) const
{
to = static_cast<T>(from);
}
template <typename F, typename T, std::enable_if_t<!std::is_signed_v<F> && !std::is_signed_v<T> && (sizeof(F) > sizeof(T))>* = nullptr>
void convertToUnsigned(const F& from, T& to) const
{
convertToSmallerUnsigned(from, to);
}
template <typename F, typename T, std::enable_if_t<std::is_signed_v<F> && !std::is_signed_v<T>>* = nullptr>
void convertToUnsigned(const F& from, T& to) const
{
convertSignedToUnsigned(from, to);
}
template <typename F, typename T,
std::enable_if_t<std::is_integral_v<F>, bool> = true,
std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
@ -787,6 +823,287 @@ public:
return typeid(T);
}
void convert(Int8& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToSigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(Int16& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToSigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(Int32& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToSigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(Int64& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToSigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(UInt8& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToUnsigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(UInt16& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToUnsigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(UInt32& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToUnsigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(UInt64& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToUnsigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
#ifdef POCO_INT64_IS_LONG
void convert(long long& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToSigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
void convert(unsigned long long& val) const
{
if constexpr (std::is_enum_v<T>)
{
convertToUnsigned(std::underlying_type_t<T>(_val), val);
}
else
{
VarHolder::convert(val);
}
}
#endif
void convert(bool& val) const
{
if constexpr (std::is_enum_v<T>)
{
val = (std::underlying_type_t<T>(_val) != 0);
}
else
{
VarHolder::convert(val);
}
}
void convert(float& val) const
{
if constexpr (std::is_enum_v<T>)
{
val = static_cast<float>(_val);
}
else
{
VarHolder::convert(val);
}
}
void convert(double& val) const
{
if constexpr (std::is_enum_v<T>)
{
val = static_cast<double>(_val);
}
else
{
VarHolder::convert(val);
}
}
void convert(char& val) const
{
if constexpr (std::is_enum_v<T>)
{
val = static_cast<char>(_val);
}
else
{
VarHolder::convert(val);
}
}
void convert(std::string& val) const
{
if constexpr (std::is_enum_v<T>)
{
val = NumberFormatter::format(std::underlying_type_t<T>(_val));
}
else
{
VarHolder::convert(val);
}
}
void convert(Poco::UTF16String& val) const
{
if constexpr (std::is_enum_v<T>)
{
std::string str = NumberFormatter::format(std::underlying_type_t<T>(_val));
Poco::UnicodeConverter::convert(str, val);
}
else
{
VarHolder::convert(val);
}
}
bool isArray() const
{
if constexpr (std::is_enum_v<T>)
{
return false;
}
else
{
return VarHolder::isArray();
}
}
bool isStruct() const
{
if constexpr (std::is_enum_v<T>)
{
return false;
}
else
{
return VarHolder::isStruct();
}
}
bool isInteger() const
{
if constexpr (std::is_enum_v<T>)
{
return std::numeric_limits<std::underlying_type_t<T>>::is_integer;
}
else
{
return VarHolder::isInteger();
}
}
bool isSigned() const
{
if constexpr (std::is_enum_v<T>)
{
return std::numeric_limits<std::underlying_type_t<T>>::is_signed;
}
else
{
return VarHolder::isSigned();
}
}
bool isNumeric() const
{
if constexpr (std::is_enum_v<T>)
{
return std::numeric_limits<std::underlying_type_t<T>>::is_specialized;
}
else
{
return VarHolder::isNumeric();
}
}
bool isBoolean() const
{
if constexpr (std::is_enum_v<T>)
{
return false;
}
else
{
return VarHolder::isBoolean();
}
}
bool isString() const
{
if constexpr (std::is_enum_v<T>)
{
return false;
}
else
{
return VarHolder::isString();
}
}
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
{
return cloneHolder(pVarHolder, _val);

View File

@ -1644,6 +1644,103 @@ void VarTest::testULongLong()
}
void VarTest::testEnumType()
{
enum class src {
value = 32
};
Var a1 = src::value;
assertTrue (a1.type() == typeid(src));
std::string s1;
Poco::Int8 s2;
Poco::Int16 s3;
Poco::Int32 s4;
Poco::Int64 s5;
Poco::UInt8 s6;
Poco::UInt16 s7;
Poco::UInt32 s8;
Poco::UInt64 s9;
float s10;
double s11;
bool s12;
char s13;
a1.convert(s1);
a1.convert(s2);
a1.convert(s3);
a1.convert(s4);
a1.convert(s5);
a1.convert(s6);
a1.convert(s7);
a1.convert(s8);
a1.convert(s9);
a1.convert(s10);
a1.convert(s11);
a1.convert(s12);
a1.convert(s13);
long s14;
unsigned long s15;
long long s16;
unsigned long long s17;
a1.convert(s14);
a1.convert(s15);
a1.convert(s16);
a1.convert(s17);
assertTrue (s14 == 32);
assertTrue (s15 == 32);
assertTrue (s16 == 32);
assertTrue (s17 == 32);
assertTrue (s1 == "32");
assertTrue (s2 == 32);
assertTrue (s3 == 32);
assertTrue (s4 == 32);
assertTrue (s5 == 32);
assertTrue (s6 == 32);
assertTrue (s7 == 32);
assertTrue (s8 == 32);
assertTrue (s9 == 32);
assertTrue (s10 == 32.0f);
assertTrue (s11 == 32.0);
assertTrue (s12);
assertTrue (s13 == ' ');
Var a2(a1);
std::string t2;
a2.convert(t2);
assertTrue (s1 == t2);
src value = a1.extract<src>();
assertTrue (value == src::value);
try
{
POCO_UNUSED Int16 value2; value2 = a1.extract<Int16>();
fail("bad cast - must throw");
}
catch (Poco::BadCastException&)
{
}
Var a3 = a1 + 1;
assertTrue (a3 == 33);
a3 = a1 - 1;
assertTrue (a3 == 31);
a3 += 1;
assertTrue (a3 == 32);
a3 -= 1;
assertTrue (a3 == 31);
a3 = a1 / 2;
assertTrue (a3 == 16);
a3 = a1 * 2;
assertTrue (a3 == 64);
a3 /= 2;
assertTrue (a3 == 32);
a3 *= 2;
assertTrue (a3 == 64);
}
void VarTest::testUDT()
{
Dummy d0;
@ -3375,6 +3472,7 @@ CppUnit::Test* VarTest::suite()
CppUnit_addTest(pSuite, VarTest, testEmpty);
CppUnit_addTest(pSuite, VarTest, testIterator);
CppUnit_addTest(pSuite, VarTest, testVarVisitor);
CppUnit_addTest(pSuite, VarTest, testEnumType);
return pSuite;
}

View File

@ -42,6 +42,7 @@ public:
void testULong();
void testLongLong();
void testULongLong();
void testEnumType();
void testString();
void testUDT();
void testConversionOperator();

View File

@ -2369,7 +2369,178 @@ void JSONTest::testRemove()
assertTrue(nl[1] == "baz");
}
void JSONTest::testEnum()
{
enum SAMPLE_ENUM
{
SE_VALUE = 42
};
enum class SAMPLE_ENUM_CLASS
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_I8: Poco::Int8
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_I16: Poco::Int16
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_I32: Poco::Int32
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_I64: Poco::Int64
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_UI8: Poco::UInt8
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_UI16: Poco::UInt16
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_UI32: Poco::UInt32
{
VALUE = 42
};
enum class SAMPLE_ENUM_CLASS_UI64: Poco::UInt64
{
VALUE = 42
};
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("simple_enum", SE_VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"simple_enum\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM se = obj->get("simple_enum").extract<SAMPLE_ENUM>();
assertTrue(se == SE_VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class", SAMPLE_ENUM_CLASS::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS se = obj->get("enum_class").extract<SAMPLE_ENUM_CLASS>();
assertTrue(se == SAMPLE_ENUM_CLASS::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_i8", SAMPLE_ENUM_CLASS_I8::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_i8\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_I8 se = obj->get("enum_class_i8").extract<SAMPLE_ENUM_CLASS_I8>();
assertTrue(se == SAMPLE_ENUM_CLASS_I8::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_i16", SAMPLE_ENUM_CLASS_I16::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_i16\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_I16 se = obj->get("enum_class_i16").extract<SAMPLE_ENUM_CLASS_I16>();
assertTrue(se == SAMPLE_ENUM_CLASS_I16::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_i32", SAMPLE_ENUM_CLASS_I32::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_i32\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_I32 se = obj->get("enum_class_i32").extract<SAMPLE_ENUM_CLASS_I32>();
assertTrue(se == SAMPLE_ENUM_CLASS_I32::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_i64", SAMPLE_ENUM_CLASS_I64::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_i64\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_I64 se = obj->get("enum_class_i64").extract<SAMPLE_ENUM_CLASS_I64>();
assertTrue(se == SAMPLE_ENUM_CLASS_I64::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_ui8", SAMPLE_ENUM_CLASS_UI8::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_ui8\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_UI8 se = obj->get("enum_class_ui8").extract<SAMPLE_ENUM_CLASS_UI8>();
assertTrue(se == SAMPLE_ENUM_CLASS_UI8::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_ui16", SAMPLE_ENUM_CLASS_UI16::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_ui16\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_UI16 se = obj->get("enum_class_ui16").extract<SAMPLE_ENUM_CLASS_UI16>();
assertTrue(se == SAMPLE_ENUM_CLASS_UI16::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_ui32", SAMPLE_ENUM_CLASS_UI32::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_ui32\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_UI32 se = obj->get("enum_class_ui32").extract<SAMPLE_ENUM_CLASS_UI32>();
assertTrue(se == SAMPLE_ENUM_CLASS_UI32::VALUE);
}
{
Poco::JSON::Object::Ptr obj = new Poco::JSON::Object();
obj->set("enum_class_ui64", SAMPLE_ENUM_CLASS_UI64::VALUE);
Poco::Dynamic::Var var(obj);
std::string expected = "{\"enum_class_ui64\":42}";
std::string result = var.convert<std::string>();
assertEquals(expected, result);
SAMPLE_ENUM_CLASS_UI64 se = obj->get("enum_class_ui64").extract<SAMPLE_ENUM_CLASS_UI64>();
assertTrue(se == SAMPLE_ENUM_CLASS_UI64::VALUE);
}
}
CppUnit::Test* JSONTest::suite()
{
@ -2424,6 +2595,7 @@ CppUnit::Test* JSONTest::suite()
CppUnit_addTest(pSuite, JSONTest, testCopy);
CppUnit_addTest(pSuite, JSONTest, testMove);
CppUnit_addTest(pSuite, JSONTest, testRemove);
CppUnit_addTest(pSuite, JSONTest, testEnum);
return pSuite;
}

View File

@ -86,6 +86,8 @@ public:
void testMove();
void testRemove();
void testEnum();
void setUp();
void tearDown();