allow nf7::Value to hold a custom data type
This commit is contained in:
parent
1f3faa1dbb
commit
b1a19b96ba
@ -41,6 +41,7 @@ void TaskContext::Push(const nf7::Value& v) noexcept {
|
|||||||
v.is<nf7::Value::Real>() ? "real":
|
v.is<nf7::Value::Real>() ? "real":
|
||||||
v.is<nf7::Value::Buffer>() ? "buffer":
|
v.is<nf7::Value::Buffer>() ? "buffer":
|
||||||
v.is<nf7::Value::Object>() ? "object":
|
v.is<nf7::Value::Object>() ? "object":
|
||||||
|
v.is<nf7::Value::SharedData>() ? "data":
|
||||||
"unknown");
|
"unknown");
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
|
@ -147,7 +147,13 @@ class Value final {
|
|||||||
std::shared_ptr<const Pair[]> pairs_;
|
std::shared_ptr<const Pair[]> pairs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Variant = std::variant<Null, Integer, Real, Buffer, Object>;
|
class Data {
|
||||||
|
public:
|
||||||
|
virtual ~Data() = default;
|
||||||
|
};
|
||||||
|
using SharedData = std::shared_ptr<Data>;
|
||||||
|
|
||||||
|
using Variant = std::variant<Null, Integer, Real, Buffer, Object, SharedData>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Value MakeNull(Null v = {}) noexcept { return v; }
|
static Value MakeNull(Null v = {}) noexcept { return v; }
|
||||||
@ -217,6 +223,14 @@ class Value final {
|
|||||||
return MakeArray(v.begin(), v.end());
|
return MakeArray(v.begin(), v.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
static Value MakeSharedData(Args&&... args)
|
||||||
|
try {
|
||||||
|
return Value {std::make_shared<T>(std::forward<Args>(args)...)};
|
||||||
|
} catch (const std::bad_alloc&) {
|
||||||
|
throw MemoryException {};
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value() noexcept : var_(Null {}) { }
|
Value() noexcept : var_(Null {}) { }
|
||||||
Value(Null v) noexcept : var_(v) { }
|
Value(Null v) noexcept : var_(v) { }
|
||||||
@ -226,6 +240,8 @@ class Value final {
|
|||||||
Value(const Buffer& v) noexcept : var_(v) { }
|
Value(const Buffer& v) noexcept : var_(v) { }
|
||||||
Value(Object&& v) noexcept : var_(std::move(v)) { }
|
Value(Object&& v) noexcept : var_(std::move(v)) { }
|
||||||
Value(const Object& v) noexcept : var_(v) { }
|
Value(const Object& v) noexcept : var_(v) { }
|
||||||
|
Value(SharedData&& v) noexcept : var_(std::move(v)) { }
|
||||||
|
Value(const SharedData& v) noexcept : var_(v) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(const Value&) = default;
|
Value(const Value&) = default;
|
||||||
@ -277,6 +293,16 @@ class Value final {
|
|||||||
throw Exception {"value is not a number", location};
|
throw Exception {"value is not a number", location};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<T> data(
|
||||||
|
std::source_location loc = std::source_location::current()) const {
|
||||||
|
static_assert(std::is_base_of_v<Data, T>);
|
||||||
|
|
||||||
|
const auto ret = std::dynamic_pointer_cast<T>(as<SharedData>(loc));
|
||||||
|
return nullptr != ret? ret:
|
||||||
|
throw Exception {"incompatible data type", loc};
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Variant var_;
|
Variant var_;
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class CustomData1 : public nf7::Value::Data { };
|
||||||
|
class CustomData2 : public nf7::Value::Data { };
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
TEST(Value, NullAsNull) {
|
TEST(Value, NullAsNull) {
|
||||||
const auto v = nf7::Value::MakeNull();
|
const auto v = nf7::Value::MakeNull();
|
||||||
EXPECT_TRUE(v.is<nf7::Value::Null>());
|
EXPECT_TRUE(v.is<nf7::Value::Null>());
|
||||||
@ -11,6 +19,7 @@ TEST(Value, NullAsNull) {
|
|||||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||||
}
|
}
|
||||||
TEST(Value, NullAsInvalid) {
|
TEST(Value, NullAsInvalid) {
|
||||||
const auto v = nf7::Value::MakeNull();
|
const auto v = nf7::Value::MakeNull();
|
||||||
@ -18,6 +27,7 @@ TEST(Value, NullAsInvalid) {
|
|||||||
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||||
}
|
}
|
||||||
TEST(Value, NullEqual) {
|
TEST(Value, NullEqual) {
|
||||||
EXPECT_EQ(nf7::Value::MakeNull(), nf7::Value::MakeNull());
|
EXPECT_EQ(nf7::Value::MakeNull(), nf7::Value::MakeNull());
|
||||||
@ -27,6 +37,7 @@ TEST(Value, NullNotEqual) {
|
|||||||
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeReal(0));
|
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeReal(0));
|
||||||
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeBuffer<uint8_t>({}));
|
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeObject({}));
|
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeSharedData<CustomData1>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, IntegerAsInteger) {
|
TEST(Value, IntegerAsInteger) {
|
||||||
@ -37,6 +48,7 @@ TEST(Value, IntegerAsInteger) {
|
|||||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||||
|
|
||||||
EXPECT_EQ(v.as<nf7::Value::Integer>(), nf7::Value::Integer {777});
|
EXPECT_EQ(v.as<nf7::Value::Integer>(), nf7::Value::Integer {777});
|
||||||
}
|
}
|
||||||
@ -46,6 +58,7 @@ TEST(Value, IntegerAsInvalid) {
|
|||||||
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||||
}
|
}
|
||||||
TEST(Value, IntegerAsValidNum) {
|
TEST(Value, IntegerAsValidNum) {
|
||||||
const nf7::Value v = nf7::Value::MakeInteger(777);
|
const nf7::Value v = nf7::Value::MakeInteger(777);
|
||||||
@ -66,6 +79,7 @@ TEST(Value, IntegerNotEqual) {
|
|||||||
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeReal(0));
|
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeReal(0));
|
||||||
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeBuffer<uint8_t>({}));
|
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeObject({}));
|
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeSharedData<CustomData1>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, RealAsReal) {
|
TEST(Value, RealAsReal) {
|
||||||
@ -76,6 +90,7 @@ TEST(Value, RealAsReal) {
|
|||||||
EXPECT_TRUE(v.is<nf7::Value::Real>());
|
EXPECT_TRUE(v.is<nf7::Value::Real>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||||
|
|
||||||
EXPECT_EQ(v.as<nf7::Value::Real>(), nf7::Value::Real {777});
|
EXPECT_EQ(v.as<nf7::Value::Real>(), nf7::Value::Real {777});
|
||||||
}
|
}
|
||||||
@ -85,6 +100,7 @@ TEST(Value, RealAsInvalid) {
|
|||||||
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||||
}
|
}
|
||||||
TEST(Value, RealAsValidNum) {
|
TEST(Value, RealAsValidNum) {
|
||||||
const auto v = nf7::Value::MakeReal(777);
|
const auto v = nf7::Value::MakeReal(777);
|
||||||
@ -105,6 +121,7 @@ TEST(Value, RealNotEqual) {
|
|||||||
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeInteger(1));
|
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeInteger(1));
|
||||||
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeBuffer<uint8_t>({}));
|
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeObject({}));
|
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeSharedData<CustomData1>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, BufferAsBuffer) {
|
TEST(Value, BufferAsBuffer) {
|
||||||
@ -114,6 +131,7 @@ TEST(Value, BufferAsBuffer) {
|
|||||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||||
EXPECT_TRUE(v.is<nf7::Value::Buffer>());
|
EXPECT_TRUE(v.is<nf7::Value::Buffer>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||||
}
|
}
|
||||||
TEST(Value, BufferAsInvalid) {
|
TEST(Value, BufferAsInvalid) {
|
||||||
const auto v = nf7::Value::MakeBuffer<uint8_t>({});
|
const auto v = nf7::Value::MakeBuffer<uint8_t>({});
|
||||||
@ -121,6 +139,7 @@ TEST(Value, BufferAsInvalid) {
|
|||||||
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||||
}
|
}
|
||||||
TEST(Value, BufferEqual) {
|
TEST(Value, BufferEqual) {
|
||||||
const auto v = nf7::Value::MakeBuffer<uint8_t>({});
|
const auto v = nf7::Value::MakeBuffer<uint8_t>({});
|
||||||
@ -133,6 +152,7 @@ TEST(Value, BufferNotEqual) {
|
|||||||
EXPECT_NE(nf7::Value::MakeBuffer<uint8_t>({}),
|
EXPECT_NE(nf7::Value::MakeBuffer<uint8_t>({}),
|
||||||
nf7::Value::MakeBuffer<uint8_t>({}));
|
nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
EXPECT_NE(nf7::Value::MakeBuffer<uint8_t>({}), nf7::Value::MakeObject({}));
|
EXPECT_NE(nf7::Value::MakeBuffer<uint8_t>({}), nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(nf7::Value::MakeBuffer<uint8_t>({}), nf7::Value::MakeSharedData<CustomData1>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, ObjectAsObject) {
|
TEST(Value, ObjectAsObject) {
|
||||||
@ -142,6 +162,7 @@ TEST(Value, ObjectAsObject) {
|
|||||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||||
EXPECT_TRUE(v.is<nf7::Value::Object>());
|
EXPECT_TRUE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||||
}
|
}
|
||||||
TEST(Value, ObjectAsInvalid) {
|
TEST(Value, ObjectAsInvalid) {
|
||||||
const auto v = nf7::Value::MakeObject({});
|
const auto v = nf7::Value::MakeObject({});
|
||||||
@ -149,6 +170,7 @@ TEST(Value, ObjectAsInvalid) {
|
|||||||
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||||
}
|
}
|
||||||
TEST(Value, ObjectEqual) {
|
TEST(Value, ObjectEqual) {
|
||||||
const auto v = nf7::Value::MakeObject({});
|
const auto v = nf7::Value::MakeObject({});
|
||||||
@ -160,6 +182,53 @@ TEST(Value, ObjectNotEqual) {
|
|||||||
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeReal(0));
|
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeReal(0));
|
||||||
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeBuffer<uint8_t>({}));
|
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeObject({}));
|
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(nf7::Value::MakeObject({}), nf7::Value::MakeSharedData<CustomData1>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Value, DataAsCompatibleData) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::Null>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::Integer>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||||
|
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||||
|
EXPECT_TRUE(v.is<nf7::Value::SharedData>());
|
||||||
|
|
||||||
|
EXPECT_NE(v.data<CustomData1>(), nullptr);
|
||||||
|
}
|
||||||
|
TEST(Value, DataAsIncompatibleData) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_THROW(v.data<CustomData2>(), nf7::Exception);
|
||||||
|
}
|
||||||
|
TEST(Value, DataAsInvalid) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Null>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
}
|
||||||
|
TEST(Value, DataAsIncompatibleType) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Null>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Integer>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Real>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||||
|
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||||
|
}
|
||||||
|
TEST(Value, DataEqual) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_EQ(v, v);
|
||||||
|
}
|
||||||
|
TEST(Value, DataNotEqual) {
|
||||||
|
const auto v = nf7::Value::MakeSharedData<CustomData1>();
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeNull());
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeInteger(0));
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeReal(0));
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeBuffer<uint8_t>({}));
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeObject({}));
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeSharedData<CustomData1>());
|
||||||
|
EXPECT_NE(v, nf7::Value::MakeSharedData<CustomData2>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ValueBuffer, Make) {
|
TEST(ValueBuffer, Make) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user