Commit d99c0b4c authored by Kenton Varda's avatar Kenton Varda

Remove DynamicObject. DynamicValue can now contain an ObjectPointer to represent object fields.

parent 2b643930
......@@ -1811,13 +1811,13 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
if (constValue.getType() == DynamicValue::OBJECT) {
// We need to assign an appropriate schema to this object.
DynamicObject::Reader objValue = constValue.as<DynamicObject>();
ObjectPointer::Reader objValue = constValue.as<ObjectPointer>();
auto constType = constReader.getType();
switch (constType.which()) {
case schema::Type::STRUCT:
KJ_IF_MAYBE(structSchema, resolver.resolveBootstrapSchema(
constType.getStruct().getTypeId())) {
constValue = objValue.as(structSchema->asStruct());
constValue = objValue.getAs<DynamicStruct>(structSchema->asStruct());
} else {
// The struct's schema is broken for reasons already reported.
return nullptr;
......@@ -1825,7 +1825,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
break;
case schema::Type::LIST:
KJ_IF_MAYBE(listSchema, makeListSchemaOf(constType.getList().getElementType())) {
constValue = objValue.as(*listSchema);
constValue = objValue.getAs<DynamicList>(*listSchema);
} else {
// The list's schema is broken for reasons already reported.
return nullptr;
......
......@@ -191,11 +191,14 @@ TEST(DynamicApi, DynamicGenericObjects) {
checkTestMessage(root.asReader().as<test::TestObject>().getObjectField().getAs<TestAllTypes>());
checkDynamicTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<TestAllTypes>()));
root.get("objectField").as<ObjectPointer>().asReader()
.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.getObject("objectField", Schema::from<TestAllTypes>()));
......@@ -218,13 +221,16 @@ TEST(DynamicApi, DynamicGenericObjects) {
}
checkList<uint32_t>(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
root.asReader().get("objectField").as<ObjectPointer>()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<List<uint32_t>>()),
root.get("objectField").as<ObjectPointer>().asReader()
.getAs<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.getObject("objectField", Schema::from<List<uint32_t>>()),
......
This diff is collapsed.
This diff is collapsed.
......@@ -1617,19 +1617,19 @@ struct WireHelpers {
}
}
static KJ_ALWAYS_INLINE(void setObjectPointer(
SegmentBuilder* segment, WirePointer* ref, ObjectReader value)) {
static KJ_ALWAYS_INLINE(SegmentAnd<word*> setObjectPointer(
SegmentBuilder* segment, WirePointer* ref, ObjectReader value,
BuilderArena* orphanArena = nullptr)) {
switch (value.kind) {
case ObjectKind::NULL_POINTER:
memset(ref, 0, sizeof(*ref));
break;
return { segment, nullptr };
case ObjectKind::STRUCT:
setStructPointer(segment, ref, value.structReader);
break;
return setStructPointer(segment, ref, value.structReader, orphanArena);
case ObjectKind::LIST:
setListPointer(segment, ref, value.listReader);
break;
return setListPointer(segment, ref, value.listReader, orphanArena);
}
KJ_UNREACHABLE;
}
static void adopt(SegmentBuilder* segment, WirePointer* ref, OrphanBuilder&& value) {
......@@ -2139,7 +2139,7 @@ void PointerBuilder::setList(const ListReader& value) {
}
void PointerBuilder::setObject(const ObjectReader& value) {
return WireHelpers::setObjectPointer(segment, pointer, value);
WireHelpers::setObjectPointer(segment, pointer, value);
}
void PointerBuilder::adopt(OrphanBuilder&& value) {
......@@ -2159,6 +2159,18 @@ bool PointerBuilder::isNull() {
return pointer->isNull();
}
void PointerBuilder::transferFrom(PointerBuilder other) {
WireHelpers::transferPointer(segment, pointer, other.segment, other.pointer);
}
void PointerBuilder::copyFrom(PointerReader other) {
WireHelpers::setObjectPointer(segment, pointer, other.getObject(nullptr));
}
PointerReader PointerBuilder::asReader() const {
return PointerReader(segment, pointer, std::numeric_limits<int>::max());
}
// =======================================================================================
// PointerReader
......@@ -2541,6 +2553,15 @@ OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, ListReader copyFrom) {
return result;
}
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, PointerReader copyFrom) {
OrphanBuilder result;
auto allocation = WireHelpers::setObjectPointer(
nullptr, result.tagAsPtr(), copyFrom.getObject(nullptr), arena);
result.segment = allocation.segment;
result.location = reinterpret_cast<word*>(allocation.value);
return result;
}
OrphanBuilder OrphanBuilder::copy(BuilderArena* arena, Text::Reader copyFrom) {
OrphanBuilder result;
auto allocation = WireHelpers::setTextPointer(
......
......@@ -316,6 +316,8 @@ public:
void copyFrom(PointerReader other);
// Equivalent to `set(other.get())`.
PointerReader asReader() const;
private:
SegmentBuilder* segment; // Memory segment in which the pointer resides.
WirePointer* pointer; // Pointer to the pointer.
......@@ -360,6 +362,7 @@ private:
friend class StructReader;
friend class ListReader;
friend class PointerBuilder;
};
// -------------------------------------------------------------------
......@@ -739,6 +742,7 @@ public:
static OrphanBuilder copy(BuilderArena* arena, StructReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, ListReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, PointerReader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, Text::Reader copyFrom);
static OrphanBuilder copy(BuilderArena* arena, Data::Reader copyFrom);
......
......@@ -26,11 +26,13 @@
#include "layout.h"
#include "pointer-helpers.h"
#include "orphan.h"
namespace capnp {
class StructSchema;
class ListSchema;
class Orphanage;
struct ObjectPointer {
// Reader/Builder for the `Object` field type, i.e. a pointer that can point to an arbitrary
......@@ -38,6 +40,8 @@ struct ObjectPointer {
class Reader {
public:
typedef ObjectPointer Reads;
Reader() = default;
inline Reader(_::PointerReader reader): reader(reader) {}
......@@ -57,10 +61,14 @@ struct ObjectPointer {
private:
_::PointerReader reader;
friend struct ObjectPointer;
friend class Orphanage;
};
class Builder {
public:
typedef ObjectPointer Builds;
Builder() = delete;
inline Builder(decltype(nullptr)) {}
inline Builder(_::PointerBuilder builder): builder(builder) {}
......@@ -107,6 +115,9 @@ struct ObjectPointer {
inline void setAs(std::initializer_list<ReaderFor<ListElementType<T>>> list);
// Valid for T = List<?>.
inline void set(Reader value) { builder.copyFrom(value.reader); }
// Set to a copy of another ObjectPointer.
template <typename T>
inline void adopt(Orphan<T>&& orphan);
// Valid for T = any generated struct type, List<U>, Text, Data, DynamicList, DynamicStruct,
......@@ -124,11 +135,69 @@ struct ObjectPointer {
inline Orphan<T> disownAs(ListSchema schema);
// Only valid for T = DynamicList. Requires `#include <capnp/dynamic.h>`.
inline Orphan<ObjectPointer> disown();
// Disown without a type.
inline Reader asReader() const { return Reader(builder.asReader()); }
inline operator Reader() const { return Reader(builder.asReader()); }
private:
_::PointerBuilder builder;
};
};
template <>
class Orphan<ObjectPointer> {
// An orphaned object of unknown type.
public:
Orphan() = default;
KJ_DISALLOW_COPY(Orphan);
Orphan(Orphan&&) = default;
Orphan& operator=(Orphan&&) = default;
// It's not possible to get an ObjectPointer::{Reader,Builder} directly since there is no
// underlying pointer (the pointer would normally live in the parent, but this object is
// orphaned). It is possible, however, to request readers/builders.
template <typename T>
inline typename T::Builder getAs();
template <typename T>
inline typename T::Builder getAs(StructSchema schema);
template <typename T>
inline typename T::Builder getAs(ListSchema schema);
template <typename T>
inline typename T::Reader getAsReader() const;
template <typename T>
inline typename T::Reader getAsReader(StructSchema schema) const;
template <typename T>
inline typename T::Reader getAsReader(ListSchema schema) const;
template <typename T>
inline Orphan<T> releaseAs();
template <typename T>
inline Orphan<T> releaseAs(StructSchema schema);
template <typename T>
inline Orphan<T> releaseAs(ListSchema schema);
// Down-cast the orphan to a specific type.
inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
private:
_::OrphanBuilder builder;
inline Orphan(_::OrphanBuilder&& builder)
: builder(kj::mv(builder)) {}
template <typename, Kind>
friend struct _::PointerHelpers;
friend class Orphanage;
template <typename U>
friend class Orphan;
friend class ObjectPointer::Builder;
};
// =======================================================================================
// Inline implementation details
......@@ -185,6 +254,33 @@ inline Orphan<T> ObjectPointer::Builder::disownAs() {
return _::PointerHelpers<T>::disown(builder);
}
inline Orphan<ObjectPointer> ObjectPointer::Builder::disown() {
return Orphan<ObjectPointer>(builder.disown());
}
template <> struct ReaderFor_ <ObjectPointer, Kind::UNKNOWN> { typedef ObjectPointer::Reader Type; };
template <> struct BuilderFor_<ObjectPointer, Kind::UNKNOWN> { typedef ObjectPointer::Builder Type; };
template <>
struct Orphanage::GetInnerReader<ObjectPointer, Kind::UNKNOWN> {
static inline _::PointerReader apply(const ObjectPointer::Reader& t) {
return t.reader;
}
};
template <typename T>
inline typename T::Builder Orphan<ObjectPointer>::getAs() {
return _::OrphanGetImpl<T>::apply(builder);
}
template <typename T>
inline typename T::Reader Orphan<ObjectPointer>::getAsReader() const {
return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T>
inline Orphan<T> Orphan<ObjectPointer>::releaseAs() {
return Orphan<T>(kj::mv(builder));
}
} // namespace capnp
#endif // CAPNP_OBJECT_H_
......@@ -529,14 +529,12 @@ TEST(Orphans, DynamicObject) {
initTestMessage(root.getObjectField().initAs<TestAllTypes>());
EXPECT_TRUE(root.hasObjectField());
Orphan<DynamicValue> orphan = root.getObjectField().disownAs<DynamicObject>();
Orphan<DynamicValue> orphan = root.getObjectField().disown();
EXPECT_EQ(DynamicValue::OBJECT, orphan.getType());
checkTestMessage(orphan.getReader().as<DynamicObject>().as<TestAllTypes>());
Orphan<DynamicObject> objectOrphan = orphan.releaseAs<DynamicObject>();
Orphan<ObjectPointer> objectOrphan = orphan.releaseAs<ObjectPointer>();
checkTestMessage(objectOrphan.getAs<TestAllTypes>());
checkDynamicTestMessage(objectOrphan.getAs(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(objectOrphan.getAs<DynamicStruct>(Schema::from<TestAllTypes>()));
}
TEST(Orphans, DynamicDisown) {
......
......@@ -267,8 +267,6 @@ kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(valu
kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(DynamicEnum value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value) { return stringify(value); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment