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::Buffer>() ? "buffer":
|
||||
v.is<nf7::Value::Object>() ? "object":
|
||||
v.is<nf7::Value::SharedData>() ? "data":
|
||||
"unknown");
|
||||
return 1;
|
||||
});
|
||||
|
@ -147,7 +147,13 @@ class Value final {
|
||||
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:
|
||||
static Value MakeNull(Null v = {}) noexcept { return v; }
|
||||
@ -217,6 +223,14 @@ class Value final {
|
||||
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:
|
||||
Value() noexcept : var_(Null {}) { }
|
||||
Value(Null v) noexcept : var_(v) { }
|
||||
@ -226,6 +240,8 @@ class Value final {
|
||||
Value(const Buffer& v) noexcept : var_(v) { }
|
||||
Value(Object&& v) noexcept : var_(std::move(v)) { }
|
||||
Value(const Object& v) noexcept : var_(v) { }
|
||||
Value(SharedData&& v) noexcept : var_(std::move(v)) { }
|
||||
Value(const SharedData& v) noexcept : var_(v) { }
|
||||
|
||||
public:
|
||||
Value(const Value&) = default;
|
||||
@ -277,6 +293,16 @@ class Value final {
|
||||
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:
|
||||
Variant var_;
|
||||
};
|
||||
|
@ -4,6 +4,14 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class CustomData1 : public nf7::Value::Data { };
|
||||
class CustomData2 : public nf7::Value::Data { };
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
TEST(Value, NullAsNull) {
|
||||
const auto v = nf7::Value::MakeNull();
|
||||
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::Buffer>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||
}
|
||||
TEST(Value, NullAsInvalid) {
|
||||
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::Buffer>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||
}
|
||||
TEST(Value, NullEqual) {
|
||||
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::MakeBuffer<uint8_t>({}));
|
||||
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeObject({}));
|
||||
EXPECT_NE(nf7::Value::MakeNull(), nf7::Value::MakeSharedData<CustomData1>());
|
||||
}
|
||||
|
||||
TEST(Value, IntegerAsInteger) {
|
||||
@ -37,6 +48,7 @@ TEST(Value, IntegerAsInteger) {
|
||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||
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});
|
||||
}
|
||||
@ -46,6 +58,7 @@ TEST(Value, IntegerAsInvalid) {
|
||||
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);
|
||||
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||
}
|
||||
TEST(Value, IntegerAsValidNum) {
|
||||
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::MakeBuffer<uint8_t>({}));
|
||||
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeObject({}));
|
||||
EXPECT_NE(nf7::Value::MakeInteger(666), nf7::Value::MakeSharedData<CustomData1>());
|
||||
}
|
||||
|
||||
TEST(Value, RealAsReal) {
|
||||
@ -76,6 +90,7 @@ TEST(Value, RealAsReal) {
|
||||
EXPECT_TRUE(v.is<nf7::Value::Real>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||
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});
|
||||
}
|
||||
@ -85,6 +100,7 @@ TEST(Value, RealAsInvalid) {
|
||||
EXPECT_THROW(v.as<nf7::Value::Integer>(), 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::SharedData>(), nf7::Exception);
|
||||
}
|
||||
TEST(Value, RealAsValidNum) {
|
||||
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::MakeBuffer<uint8_t>({}));
|
||||
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeObject({}));
|
||||
EXPECT_NE(nf7::Value::MakeReal(1), nf7::Value::MakeSharedData<CustomData1>());
|
||||
}
|
||||
|
||||
TEST(Value, BufferAsBuffer) {
|
||||
@ -114,6 +131,7 @@ TEST(Value, BufferAsBuffer) {
|
||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||
EXPECT_TRUE(v.is<nf7::Value::Buffer>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::Object>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||
}
|
||||
TEST(Value, BufferAsInvalid) {
|
||||
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::Real>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::Object>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||
}
|
||||
TEST(Value, BufferEqual) {
|
||||
const auto v = nf7::Value::MakeBuffer<uint8_t>({});
|
||||
@ -133,6 +152,7 @@ TEST(Value, BufferNotEqual) {
|
||||
EXPECT_NE(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::MakeSharedData<CustomData1>());
|
||||
}
|
||||
|
||||
TEST(Value, ObjectAsObject) {
|
||||
@ -142,6 +162,7 @@ TEST(Value, ObjectAsObject) {
|
||||
EXPECT_FALSE(v.is<nf7::Value::Real>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::Buffer>());
|
||||
EXPECT_TRUE(v.is<nf7::Value::Object>());
|
||||
EXPECT_FALSE(v.is<nf7::Value::SharedData>());
|
||||
}
|
||||
TEST(Value, ObjectAsInvalid) {
|
||||
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::Real>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::Buffer>(), nf7::Exception);
|
||||
EXPECT_THROW(v.as<nf7::Value::SharedData>(), nf7::Exception);
|
||||
}
|
||||
TEST(Value, ObjectEqual) {
|
||||
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::MakeBuffer<uint8_t>({}));
|
||||
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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user