Commit ac1e532d authored by Kenton Varda's avatar Kenton Varda

Extend schema API to cover constants, test parsing of constants.

parent bc7b57a7
...@@ -1724,7 +1724,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant( ...@@ -1724,7 +1724,7 @@ kj::Maybe<DynamicValue::Reader> NodeTranslator::readConstant(
if (constValue.getType() == DynamicValue::OBJECT) { if (constValue.getType() == DynamicValue::OBJECT) {
// We need to assign an appropriate schema to this object. // We need to assign an appropriate schema to this object.
DynamicObject objValue = constValue.as<DynamicObject>(); DynamicObject::Reader objValue = constValue.as<DynamicObject>();
auto constType = constReader.getType(); auto constType = constReader.getType();
switch (constType.which()) { switch (constType.which()) {
case schema::Type::STRUCT: case schema::Type::STRUCT:
......
...@@ -193,7 +193,9 @@ TEST(DynamicApi, DynamicGenericObjects) { ...@@ -193,7 +193,9 @@ TEST(DynamicApi, DynamicGenericObjects) {
checkDynamicTestMessage( checkDynamicTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>())); root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
checkDynamicTestMessage( checkDynamicTestMessage(
root.get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>())); root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
checkDynamicTestMessage(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<TestAllTypes>()));
checkDynamicTestMessage( checkDynamicTestMessage(
root.getObject("objectField", Schema::from<TestAllTypes>())); root.getObject("objectField", Schema::from<TestAllTypes>()));
...@@ -219,7 +221,10 @@ TEST(DynamicApi, DynamicGenericObjects) { ...@@ -219,7 +221,10 @@ TEST(DynamicApi, DynamicGenericObjects) {
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()), root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u}); {123u, 456u, 789u, 123456789u});
checkList<uint32_t>( checkList<uint32_t>(
root.get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()), root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.get("objectField").as<DynamicObject>().asReader().as(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u}); {123u, 456u, 789u, 123456789u});
checkList<uint32_t>( checkList<uint32_t>(
root.getObject("objectField", Schema::from<List<uint32_t>>()), root.getObject("objectField", Schema::from<List<uint32_t>>()),
......
...@@ -125,7 +125,7 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const { ...@@ -125,7 +125,7 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
// ======================================================================================= // =======================================================================================
DynamicStruct::Reader DynamicObject::as(StructSchema schema) const { DynamicStruct::Reader DynamicObject::Reader::as(StructSchema schema) const {
if (reader.kind == _::ObjectKind::NULL_POINTER) { if (reader.kind == _::ObjectKind::NULL_POINTER) {
return DynamicStruct::Reader(schema, _::StructReader()); return DynamicStruct::Reader(schema, _::StructReader());
} }
...@@ -136,7 +136,7 @@ DynamicStruct::Reader DynamicObject::as(StructSchema schema) const { ...@@ -136,7 +136,7 @@ DynamicStruct::Reader DynamicObject::as(StructSchema schema) const {
return DynamicStruct::Reader(schema, reader.structReader); return DynamicStruct::Reader(schema, reader.structReader);
} }
DynamicList::Reader DynamicObject::as(ListSchema schema) const { DynamicList::Reader DynamicObject::Reader::as(ListSchema schema) const {
if (reader.kind == _::ObjectKind::NULL_POINTER) { if (reader.kind == _::ObjectKind::NULL_POINTER) {
return DynamicList::Reader(schema, _::ListReader()); return DynamicList::Reader(schema, _::ListReader());
} }
...@@ -206,14 +206,13 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const ...@@ -206,14 +206,13 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
switch (type.which()) { switch (type.which()) {
case schema::Type::VOID: case schema::Type::VOID:
return DynamicValue::Reader( return reader.getDataField<Void>(nonGroup.getOffset() * ELEMENTS);
reader.getDataField<Void>(nonGroup.getOffset() * ELEMENTS));
#define HANDLE_TYPE(discrim, titleCase, type) \ #define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::discrim: \ case schema::Type::discrim: \
return DynamicValue::Reader(reader.getDataField<type>( \ return reader.getDataField<type>( \
nonGroup.getOffset() * ELEMENTS, \ nonGroup.getOffset() * ELEMENTS, \
bitCast<_::Mask<type>>(dval.get##titleCase()))); bitCast<_::Mask<type>>(dval.get##titleCase()));
HANDLE_TYPE(BOOL, Bool, bool) HANDLE_TYPE(BOOL, Bool, bool)
HANDLE_TYPE(INT8, Int8, int8_t) HANDLE_TYPE(INT8, Int8, int8_t)
...@@ -232,45 +231,43 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const ...@@ -232,45 +231,43 @@ DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const
case schema::Type::ENUM: { case schema::Type::ENUM: {
uint16_t typedDval; uint16_t typedDval;
typedDval = dval.getEnum(); typedDval = dval.getEnum();
return DynamicValue::Reader(DynamicEnum( return DynamicEnum(
field.getContainingStruct().getDependency(type.getEnum()).asEnum(), field.getContainingStruct().getDependency(type.getEnum()).asEnum(),
reader.getDataField<uint16_t>(nonGroup.getOffset() * ELEMENTS, typedDval))); reader.getDataField<uint16_t>(nonGroup.getOffset() * ELEMENTS, typedDval));
} }
case schema::Type::TEXT: { case schema::Type::TEXT: {
Text::Reader typedDval = dval.getText(); Text::Reader typedDval = dval.getText();
return DynamicValue::Reader( return reader.getBlobField<Text>(nonGroup.getOffset() * POINTERS,
reader.getBlobField<Text>(nonGroup.getOffset() * POINTERS, typedDval.begin(), typedDval.size() * BYTES);
typedDval.begin(), typedDval.size() * BYTES));
} }
case schema::Type::DATA: { case schema::Type::DATA: {
Data::Reader typedDval = dval.getData(); Data::Reader typedDval = dval.getData();
return DynamicValue::Reader( return reader.getBlobField<Data>(nonGroup.getOffset() * POINTERS,
reader.getBlobField<Data>(nonGroup.getOffset() * POINTERS, typedDval.begin(), typedDval.size() * BYTES);
typedDval.begin(), typedDval.size() * BYTES));
} }
case schema::Type::LIST: { case schema::Type::LIST: {
auto elementType = type.getList(); auto elementType = type.getList();
return DynamicValue::Reader(DynamicList::Reader( return DynamicList::Reader(
ListSchema::of(elementType, field.getContainingStruct()), ListSchema::of(elementType, field.getContainingStruct()),
reader.getListField(nonGroup.getOffset() * POINTERS, reader.getListField(nonGroup.getOffset() * POINTERS,
elementSizeFor(elementType.which()), elementSizeFor(elementType.which()),
dval.getList<_::UncheckedMessage>()))); dval.getList<_::UncheckedMessage>()));
} }
case schema::Type::STRUCT: { case schema::Type::STRUCT: {
return DynamicValue::Reader(DynamicStruct::Reader( return DynamicStruct::Reader(
field.getContainingStruct().getDependency(type.getStruct()).asStruct(), field.getContainingStruct().getDependency(type.getStruct()).asStruct(),
reader.getStructField(nonGroup.getOffset() * POINTERS, reader.getStructField(nonGroup.getOffset() * POINTERS,
dval.getStruct<_::UncheckedMessage>()))); dval.getStruct<_::UncheckedMessage>()));
} }
case schema::Type::OBJECT: { case schema::Type::OBJECT: {
return DynamicValue::Reader(DynamicObject( return DynamicObject::Reader(
reader.getObjectField(nonGroup.getOffset() * POINTERS, reader.getObjectField(nonGroup.getOffset() * POINTERS,
dval.getObject<_::UncheckedMessage>()))); dval.getObject<_::UncheckedMessage>()));
} }
case schema::Type::INTERFACE: case schema::Type::INTERFACE:
...@@ -369,8 +366,8 @@ DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) { ...@@ -369,8 +366,8 @@ DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
} }
case schema::Type::OBJECT: { case schema::Type::OBJECT: {
return DynamicObject( return DynamicObject::Builder(
builder.asReader().getObjectField( builder.getObjectField(
nonGroup.getOffset() * POINTERS, nonGroup.getOffset() * POINTERS,
dval.getObject<_::UncheckedMessage>())); dval.getObject<_::UncheckedMessage>()));
} }
...@@ -890,7 +887,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const { ...@@ -890,7 +887,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
switch (schema.whichElementType()) { switch (schema.whichElementType()) {
#define HANDLE_TYPE(name, discrim, typeName) \ #define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \ case schema::Type::discrim: \
return DynamicValue::Reader(reader.getDataElement<typeName>(index * ELEMENTS)); return reader.getDataElement<typeName>(index * ELEMENTS);
HANDLE_TYPE(void, VOID, Void) HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool) HANDLE_TYPE(bool, BOOL, bool)
...@@ -907,28 +904,26 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const { ...@@ -907,28 +904,26 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case schema::Type::TEXT: case schema::Type::TEXT:
return DynamicValue::Reader(reader.getBlobElement<Text>(index * ELEMENTS)); return reader.getBlobElement<Text>(index * ELEMENTS);
case schema::Type::DATA: case schema::Type::DATA:
return DynamicValue::Reader(reader.getBlobElement<Data>(index * ELEMENTS)); return reader.getBlobElement<Data>(index * ELEMENTS);
case schema::Type::LIST: { case schema::Type::LIST: {
auto elementType = schema.getListElementType(); auto elementType = schema.getListElementType();
return DynamicValue::Reader(DynamicList::Reader( return DynamicList::Reader(elementType, reader.getListElement(
elementType, reader.getListElement( index * ELEMENTS, elementSizeFor(elementType.whichElementType())));
index * ELEMENTS, elementSizeFor(elementType.whichElementType()))));
} }
case schema::Type::STRUCT: case schema::Type::STRUCT:
return DynamicValue::Reader(DynamicStruct::Reader( return DynamicStruct::Reader(schema.getStructElementType(),
schema.getStructElementType(), reader.getStructElement(index * ELEMENTS))); reader.getStructElement(index * ELEMENTS));
case schema::Type::ENUM: case schema::Type::ENUM:
return DynamicValue::Reader(DynamicEnum( return DynamicEnum(schema.getEnumElementType(),
schema.getEnumElementType(), reader.getDataElement<uint16_t>(index * ELEMENTS))); reader.getDataElement<uint16_t>(index * ELEMENTS));
case schema::Type::OBJECT: case schema::Type::OBJECT:
return DynamicValue::Reader(DynamicObject( return DynamicObject::Reader(reader.getObjectElement(index * ELEMENTS));
reader.getObjectElement(index * ELEMENTS)));
case schema::Type::INTERFACE: case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Interfaces not implemented.") { KJ_FAIL_ASSERT("Interfaces not implemented.") {
...@@ -945,7 +940,7 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) { ...@@ -945,7 +940,7 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
switch (schema.whichElementType()) { switch (schema.whichElementType()) {
#define HANDLE_TYPE(name, discrim, typeName) \ #define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \ case schema::Type::discrim: \
return DynamicValue::Builder(builder.getDataElement<typeName>(index * ELEMENTS)); return builder.getDataElement<typeName>(index * ELEMENTS);
HANDLE_TYPE(void, VOID, Void) HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool) HANDLE_TYPE(bool, BOOL, bool)
...@@ -962,32 +957,32 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) { ...@@ -962,32 +957,32 @@ DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case schema::Type::TEXT: case schema::Type::TEXT:
return DynamicValue::Builder(builder.getBlobElement<Text>(index * ELEMENTS)); return builder.getBlobElement<Text>(index * ELEMENTS);
case schema::Type::DATA: case schema::Type::DATA:
return DynamicValue::Builder(builder.getBlobElement<Data>(index * ELEMENTS)); return builder.getBlobElement<Data>(index * ELEMENTS);
case schema::Type::LIST: { case schema::Type::LIST: {
ListSchema elementType = schema.getListElementType(); ListSchema elementType = schema.getListElementType();
if (elementType.whichElementType() == schema::Type::STRUCT) { if (elementType.whichElementType() == schema::Type::STRUCT) {
return DynamicValue::Builder(DynamicList::Builder(elementType, return DynamicList::Builder(elementType,
builder.getStructListElement( builder.getStructListElement(
index * ELEMENTS, index * ELEMENTS,
structSizeFromSchema(elementType.getStructElementType())))); structSizeFromSchema(elementType.getStructElementType())));
} else { } else {
return DynamicValue::Builder(DynamicList::Builder(elementType, return DynamicList::Builder(elementType,
builder.getListElement( builder.getListElement(
index * ELEMENTS, index * ELEMENTS,
elementSizeFor(elementType.whichElementType())))); elementSizeFor(elementType.whichElementType())));
} }
} }
case schema::Type::STRUCT: case schema::Type::STRUCT:
return DynamicValue::Builder(DynamicStruct::Builder( return DynamicStruct::Builder(schema.getStructElementType(),
schema.getStructElementType(), builder.getStructElement(index * ELEMENTS))); builder.getStructElement(index * ELEMENTS));
case schema::Type::ENUM: case schema::Type::ENUM:
return DynamicValue::Builder(DynamicEnum( return DynamicEnum(schema.getEnumElementType(),
schema.getEnumElementType(), builder.getDataElement<uint16_t>(index * ELEMENTS))); builder.getDataElement<uint16_t>(index * ELEMENTS));
case schema::Type::OBJECT: case schema::Type::OBJECT:
KJ_FAIL_ASSERT("List(Object) not supported."); KJ_FAIL_ASSERT("List(Object) not supported.");
...@@ -1103,24 +1098,24 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) { ...@@ -1103,24 +1098,24 @@ DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
return nullptr; return nullptr;
case schema::Type::TEXT: case schema::Type::TEXT:
return DynamicValue::Builder(builder.initBlobElement<Text>(index * ELEMENTS, size * BYTES)); return builder.initBlobElement<Text>(index * ELEMENTS, size * BYTES);
case schema::Type::DATA: case schema::Type::DATA:
return DynamicValue::Builder(builder.initBlobElement<Data>(index * ELEMENTS, size * BYTES)); return builder.initBlobElement<Data>(index * ELEMENTS, size * BYTES);
case schema::Type::LIST: { case schema::Type::LIST: {
auto elementType = schema.getListElementType(); auto elementType = schema.getListElementType();
if (elementType.whichElementType() == schema::Type::STRUCT) { if (elementType.whichElementType() == schema::Type::STRUCT) {
return DynamicValue::Builder(DynamicList::Builder( return DynamicList::Builder(
elementType, builder.initStructListElement( elementType, builder.initStructListElement(
index * ELEMENTS, size * ELEMENTS, index * ELEMENTS, size * ELEMENTS,
structSizeFromSchema(elementType.getStructElementType())))); structSizeFromSchema(elementType.getStructElementType())));
} else { } else {
return DynamicValue::Builder(DynamicList::Builder( return DynamicList::Builder(
elementType, builder.initListElement( elementType, builder.initListElement(
index * ELEMENTS, elementSizeFor(elementType.whichElementType()), index * ELEMENTS, elementSizeFor(elementType.whichElementType()),
size * ELEMENTS))); size * ELEMENTS));
} }
} }
...@@ -1147,6 +1142,47 @@ DynamicList::Reader DynamicList::Builder::asReader() const { ...@@ -1147,6 +1142,47 @@ DynamicList::Reader DynamicList::Builder::asReader() const {
// ======================================================================================= // =======================================================================================
DynamicValue::Reader::Reader(ConstSchema constant) {
auto typeSchema = constant.getProto().getConst().getType();
auto value = constant.getProto().getConst().getValue();
switch (typeSchema.which()) {
case schema::Type::VOID: *this = capnp::VOID; break;
case schema::Type::BOOL: *this = value.getBool(); break;
case schema::Type::INT8: *this = value.getInt8(); break;
case schema::Type::INT16: *this = value.getInt16(); break;
case schema::Type::INT32: *this = value.getInt32(); break;
case schema::Type::INT64: *this = value.getInt64(); break;
case schema::Type::UINT8: *this = value.getUint8(); break;
case schema::Type::UINT16: *this = value.getUint16(); break;
case schema::Type::UINT32: *this = value.getUint32(); break;
case schema::Type::UINT64: *this = value.getUint64(); break;
case schema::Type::FLOAT32: *this = value.getFloat32(); break;
case schema::Type::FLOAT64: *this = value.getFloat64(); break;
case schema::Type::TEXT: *this = value.getText(); break;
case schema::Type::DATA: *this = value.getData(); break;
case schema::Type::ENUM:
*this = DynamicEnum(constant.getDependency(typeSchema.getEnum()).asEnum(), value.getEnum());
break;
case schema::Type::STRUCT:
*this = value.getStruct<DynamicStruct>(
constant.getDependency(typeSchema.getStruct()).asStruct());
break;
case schema::Type::LIST:
*this = value.getList<DynamicList>(ListSchema::of(typeSchema.getList(), constant));
break;
case schema::Type::OBJECT:
*this = value.getObject<DynamicObject>();
break;
case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Constants can't have interface type.");
}
}
DynamicValue::Reader DynamicValue::Builder::asReader() const { DynamicValue::Reader DynamicValue::Builder::asReader() const {
switch (type) { switch (type) {
case UNKNOWN: return Reader(); case UNKNOWN: return Reader();
...@@ -1161,7 +1197,7 @@ DynamicValue::Reader DynamicValue::Builder::asReader() const { ...@@ -1161,7 +1197,7 @@ DynamicValue::Reader DynamicValue::Builder::asReader() const {
case ENUM: return Reader(enumValue); case ENUM: return Reader(enumValue);
case STRUCT: return Reader(structValue.asReader()); case STRUCT: return Reader(structValue.asReader());
case INTERFACE: KJ_FAIL_ASSERT("Interfaces not implemented."); return Reader(); case INTERFACE: KJ_FAIL_ASSERT("Interfaces not implemented."); return Reader();
case OBJECT: return Reader(objectValue); case OBJECT: return Reader(objectValue.asReader());
} }
KJ_FAIL_ASSERT("Missing switch case."); KJ_FAIL_ASSERT("Missing switch case.");
return Reader(); return Reader();
...@@ -1407,6 +1443,16 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init( ...@@ -1407,6 +1443,16 @@ DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
} }
} }
DynamicObject::Reader PointerHelpers<DynamicObject, Kind::UNKNOWN>::get(
StructReader reader, WirePointerCount index) {
return DynamicObject::Reader(reader.getObjectField(index, nullptr));
}
DynamicObject::Builder PointerHelpers<DynamicObject, Kind::UNKNOWN>::get(
StructBuilder builder, WirePointerCount index) {
return DynamicObject::Builder(builder.getObjectField(index, nullptr));
}
} // namespace _ (private) } // namespace _ (private)
// ------------------------------------------------------------------- // -------------------------------------------------------------------
......
...@@ -71,7 +71,11 @@ struct DynamicValue { ...@@ -71,7 +71,11 @@ struct DynamicValue {
class Builder; class Builder;
}; };
class DynamicEnum; class DynamicEnum;
class DynamicObject; struct DynamicObject {
DynamicObject() = delete;
class Reader;
class Builder;
};
struct DynamicStruct { struct DynamicStruct {
DynamicStruct() = delete; DynamicStruct() = delete;
class Reader; class Reader;
...@@ -134,19 +138,18 @@ private: ...@@ -134,19 +138,18 @@ private:
friend struct DynamicStruct; friend struct DynamicStruct;
friend struct DynamicList; friend struct DynamicList;
friend struct DynamicValue;
template <typename T> template <typename T>
friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value); friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
}; };
// ------------------------------------------------------------------- // -------------------------------------------------------------------
class DynamicObject { class DynamicObject::Reader {
// Represents an "Object" field of unknown type. This class behaves as a Reader. There is no // Represents an "Object" field of unknown type.
// equivalent Builder; you must use getObject() or initObject() on the containing struct and
// specify a type if you want to build an Object field.
public: public:
DynamicObject() = default; Reader() = default;
template <typename T> template <typename T>
inline typename T::Reader as() const { return AsImpl<T>::apply(*this); } inline typename T::Reader as() const { return AsImpl<T>::apply(*this); }
...@@ -158,7 +161,7 @@ public: ...@@ -158,7 +161,7 @@ public:
private: private:
_::ObjectReader reader; _::ObjectReader reader;
inline DynamicObject(_::ObjectReader reader): reader(reader) {} inline Reader(_::ObjectReader reader): reader(reader) {}
template <typename T, Kind kind = kind<T>()> struct AsImpl; template <typename T, Kind kind = kind<T>()> struct AsImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial // Implementation backing the as() method. Needs to be a struct to allow partial
...@@ -166,6 +169,34 @@ private: ...@@ -166,6 +169,34 @@ private:
friend struct DynamicStruct; friend struct DynamicStruct;
friend struct DynamicList; friend struct DynamicList;
template <typename T, Kind K>
friend struct _::PointerHelpers;
friend class DynamicObject::Builder;
};
class DynamicObject::Builder: kj::DisallowConstCopy {
// Represents an "Object" field of unknown type.
//
// You can't actually do anything with a DynamicObject::Builder except read it. It can't be
// converted to a Builder for any specific type because that could require initializing or
// updating the pointer that points *to* this object. Therefore, you must call
// DynamicStruct::Builder::{get,set,init}Object() and pass a type schema to build object fields.
public:
Builder() = default;
Builder(Builder&) = default;
Builder(Builder&&) = default;
Reader asReader() const { return Reader(builder.asReader()); }
private:
_::ObjectBuilder builder;
inline Builder(_::ObjectBuilder builder): builder(builder) {}
friend struct DynamicStruct;
friend struct DynamicList;
template <typename T, Kind K>
friend struct _::PointerHelpers;
}; };
// ------------------------------------------------------------------- // -------------------------------------------------------------------
...@@ -219,7 +250,7 @@ private: ...@@ -219,7 +250,7 @@ private:
template <typename T, Kind K> template <typename T, Kind K>
friend struct _::PointerHelpers; friend struct _::PointerHelpers;
friend class DynamicObject; friend struct DynamicObject;
friend class DynamicStruct::Builder; friend class DynamicStruct::Builder;
friend struct DynamicList; friend struct DynamicList;
friend class MessageReader; friend class MessageReader;
...@@ -366,7 +397,7 @@ private: ...@@ -366,7 +397,7 @@ private:
template <typename T, Kind k> template <typename T, Kind k>
friend struct _::PointerHelpers; friend struct _::PointerHelpers;
friend struct DynamicStruct; friend struct DynamicStruct;
friend class DynamicObject; friend struct DynamicObject;
friend class DynamicList::Builder; friend class DynamicList::Builder;
template <typename T, ::capnp::Kind k> template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_; friend struct ::capnp::ToDynamic_;
...@@ -428,8 +459,8 @@ private: ...@@ -428,8 +459,8 @@ private:
template <> struct ReaderFor_ <DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; }; template <> struct ReaderFor_ <DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct BuilderFor_<DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; }; template <> struct BuilderFor_<DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct ReaderFor_ <DynamicObject, Kind::UNKNOWN> { typedef DynamicObject Type; }; template <> struct ReaderFor_ <DynamicObject, Kind::UNKNOWN> { typedef DynamicObject::Reader Type; };
template <> struct BuilderFor_<DynamicObject, Kind::UNKNOWN> { typedef DynamicObject Type; }; template <> struct BuilderFor_<DynamicObject, Kind::UNKNOWN> { typedef DynamicObject::Builder Type; };
template <> struct ReaderFor_ <DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Reader Type; }; template <> struct ReaderFor_ <DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Reader Type; };
template <> struct BuilderFor_<DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Builder Type; }; template <> struct BuilderFor_<DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Builder Type; };
template <> struct ReaderFor_ <DynamicList, Kind::UNKNOWN> { typedef DynamicList::Reader Type; }; template <> struct ReaderFor_ <DynamicList, Kind::UNKNOWN> { typedef DynamicList::Reader Type; };
...@@ -461,7 +492,8 @@ public: ...@@ -461,7 +492,8 @@ public:
inline Reader(const DynamicList::Reader& value); inline Reader(const DynamicList::Reader& value);
inline Reader(DynamicEnum value); inline Reader(DynamicEnum value);
inline Reader(const DynamicStruct::Reader& value); inline Reader(const DynamicStruct::Reader& value);
inline Reader(DynamicObject value); inline Reader(const DynamicObject::Reader& value);
Reader(ConstSchema constant);
template <typename T, typename = decltype(toDynamic(kj::instance<T>()))> template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
inline Reader(T value): Reader(toDynamic(value)) {} inline Reader(T value): Reader(toDynamic(value)) {}
...@@ -505,7 +537,7 @@ private: ...@@ -505,7 +537,7 @@ private:
DynamicList::Reader listValue; DynamicList::Reader listValue;
DynamicEnum enumValue; DynamicEnum enumValue;
DynamicStruct::Reader structValue; DynamicStruct::Reader structValue;
DynamicObject objectValue; DynamicObject::Reader objectValue;
}; };
template <typename T, Kind kind = kind<T>()> struct AsImpl; template <typename T, Kind kind = kind<T>()> struct AsImpl;
...@@ -538,7 +570,7 @@ public: ...@@ -538,7 +570,7 @@ public:
inline Builder(DynamicList::Builder value); inline Builder(DynamicList::Builder value);
inline Builder(DynamicEnum value); inline Builder(DynamicEnum value);
inline Builder(DynamicStruct::Builder value); inline Builder(DynamicStruct::Builder value);
inline Builder(DynamicObject value); inline Builder(DynamicObject::Builder value);
template <typename T, typename = decltype(toDynamic(kj::instance<T>()))> template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
inline Builder(T value): Builder(toDynamic(value)) {} inline Builder(T value): Builder(toDynamic(value)) {}
...@@ -552,6 +584,13 @@ public: ...@@ -552,6 +584,13 @@ public:
Reader asReader() const; Reader asReader() const;
inline Builder(Builder& other) { memcpy(this, &other, sizeof(*this)); }
inline Builder(Builder&& other) { memcpy(this, &other, sizeof(*this)); }
static_assert(__has_trivial_copy(StructSchema) && __has_trivial_copy(ListSchema),
"Assumptions made here do not hold.");
// Hack: We know this type is trivially constructable but the use of DisallowConstCopy causes
// the compiler to believe otherwise.
private: private:
Type type; Type type;
...@@ -566,7 +605,7 @@ private: ...@@ -566,7 +605,7 @@ private:
DynamicList::Builder listValue; DynamicList::Builder listValue;
DynamicEnum enumValue; DynamicEnum enumValue;
DynamicStruct::Builder structValue; DynamicStruct::Builder structValue;
DynamicObject objectValue; DynamicObject::Builder objectValue;
}; };
template <typename T, Kind kind = kind<T>()> struct AsImpl; template <typename T, Kind kind = kind<T>()> struct AsImpl;
...@@ -577,7 +616,8 @@ private: ...@@ -577,7 +616,8 @@ private:
kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value); kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value); kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value);
kj::StringTree KJ_STRINGIFY(DynamicEnum value); kj::StringTree KJ_STRINGIFY(DynamicEnum value);
kj::StringTree KJ_STRINGIFY(const DynamicObject& value); kj::StringTree KJ_STRINGIFY(const DynamicObject::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicObject::Builder& value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value); kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value); kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value);
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value); kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value);
...@@ -726,6 +766,14 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> { ...@@ -726,6 +766,14 @@ struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
} }
}; };
template <>
struct PointerHelpers<DynamicObject, Kind::UNKNOWN> {
// DynamicObject can only be used with get().
static DynamicObject::Reader get(StructReader reader, WirePointerCount index);
static DynamicObject::Builder get(StructBuilder builder, WirePointerCount index);
};
} // namespace _ (private) } // namespace _ (private)
// ======================================================================================= // =======================================================================================
...@@ -789,7 +837,6 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint); ...@@ -789,7 +837,6 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
...@@ -802,6 +849,7 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text); ...@@ -802,6 +849,7 @@ CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct); CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
...@@ -891,15 +939,15 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> { ...@@ -891,15 +939,15 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
template <typename T> template <typename T>
struct DynamicObject::AsImpl<T, Kind::STRUCT> { struct DynamicObject::Reader::AsImpl<T, Kind::STRUCT> {
static T apply(DynamicObject value) { static T apply(DynamicObject::Reader value) {
return value.as(Schema::from<T>()).template as<T>(); return value.as(Schema::from<T>()).template as<T>();
} }
}; };
template <typename T> template <typename T>
struct DynamicObject::AsImpl<T, Kind::LIST> { struct DynamicObject::Reader::AsImpl<T, Kind::LIST> {
static T apply(DynamicObject value) { static T apply(DynamicObject::Reader value) {
return value.as(Schema::from<T>()).template as<T>(); return value.as(Schema::from<T>()).template as<T>();
} }
}; };
...@@ -960,6 +1008,13 @@ inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() { ...@@ -960,6 +1008,13 @@ inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
return *this; return *this;
} }
// -------------------------------------------------------------------
template <typename T>
ReaderFor<T> ConstSchema::as() const {
return DynamicValue::Reader(*this).as<T>();
}
} // namespace capnp } // namespace capnp
#endif // CAPNP_DYNAMIC_H_ #endif // CAPNP_DYNAMIC_H_
...@@ -2537,6 +2537,18 @@ ObjectReader ListReader::getObjectElement(ElementCount index) const { ...@@ -2537,6 +2537,18 @@ ObjectReader ListReader::getObjectElement(ElementCount index) const {
segment, checkAlignment(ptr + index * step / BITS_PER_BYTE), nullptr, nestingLimit); segment, checkAlignment(ptr + index * step / BITS_PER_BYTE), nullptr, nestingLimit);
} }
ObjectReader ObjectBuilder::asReader() const {
switch (kind) {
case ObjectKind::NULL_POINTER:
return ObjectReader();
case ObjectKind::STRUCT:
return ObjectReader(structBuilder.asReader());
case ObjectKind::LIST:
return ObjectReader(listBuilder.asReader());
}
KJ_UNREACHABLE;
}
// ======================================================================================= // =======================================================================================
// OrphanBuilder // OrphanBuilder
......
...@@ -710,6 +710,14 @@ struct ObjectBuilder { ...@@ -710,6 +710,14 @@ struct ObjectBuilder {
: kind(ObjectKind::STRUCT), structBuilder(structBuilder) {} : kind(ObjectKind::STRUCT), structBuilder(structBuilder) {}
ObjectBuilder(ListBuilder listBuilder) ObjectBuilder(ListBuilder listBuilder)
: kind(ObjectKind::LIST), listBuilder(listBuilder) {} : kind(ObjectKind::LIST), listBuilder(listBuilder) {}
ObjectReader asReader() const;
inline ObjectBuilder(ObjectBuilder& other) { memcpy(this, &other, sizeof(*this)); }
inline ObjectBuilder(ObjectBuilder&& other) { memcpy(this, &other, sizeof(*this)); }
// Hack: Compiler thinks StructBuilder and ListBuilder are non-trivially-copyable due to the
// inheritance from DisallowConstCopy, but that means the union causes ObjectBuilder's copy
// constructor to be deleted. We happen to know that trivial copying works here...
}; };
struct ObjectReader { struct ObjectReader {
......
...@@ -91,7 +91,7 @@ TEST(SchemaParser, Basic) { ...@@ -91,7 +91,7 @@ TEST(SchemaParser, Basic) {
}; };
ParsedSchema barSchema = parser.parseFile(SchemaFile::newDiskFile( ParsedSchema barSchema = parser.parseFile(SchemaFile::newDiskFile(
kj::str("foo2/bar2.capnp"), kj::str("src/foo/bar.capnp"), importPath, reader)); "foo2/bar2.capnp", "src/foo/bar.capnp", importPath, reader));
auto barProto = barSchema.getProto(); auto barProto = barSchema.getProto();
EXPECT_EQ(0x8123456789abcdefull, barProto.getId()); EXPECT_EQ(0x8123456789abcdefull, barProto.getId());
...@@ -110,24 +110,24 @@ TEST(SchemaParser, Basic) { ...@@ -110,24 +110,24 @@ TEST(SchemaParser, Basic) {
EXPECT_EQ(0x856789abcdef1234ull, getFieldTypeFileId(barFields[3])); EXPECT_EQ(0x856789abcdef1234ull, getFieldTypeFileId(barFields[3]));
auto bazSchema = parser.parseFile(SchemaFile::newDiskFile( auto bazSchema = parser.parseFile(SchemaFile::newDiskFile(
kj::str("not/used/because/already/loaded"), "not/used/because/already/loaded",
kj::str("src/foo/baz.capnp"), importPath, reader)); "src/foo/baz.capnp", importPath, reader));
EXPECT_EQ(0x823456789abcdef1ull, bazSchema.getProto().getId()); EXPECT_EQ(0x823456789abcdef1ull, bazSchema.getProto().getId());
EXPECT_EQ("foo2/baz.capnp", bazSchema.getProto().getDisplayName()); EXPECT_EQ("foo2/baz.capnp", bazSchema.getProto().getDisplayName());
auto bazStruct = bazSchema.getNested("Baz").asStruct(); auto bazStruct = bazSchema.getNested("Baz").asStruct();
EXPECT_EQ(bazStruct, barStruct.getDependency(bazStruct.getProto().getId())); EXPECT_EQ(bazStruct, barStruct.getDependency(bazStruct.getProto().getId()));
auto corgeSchema = parser.parseFile(SchemaFile::newDiskFile( auto corgeSchema = parser.parseFile(SchemaFile::newDiskFile(
kj::str("not/used/because/already/loaded"), "not/used/because/already/loaded",
kj::str("src/qux/corge.capnp"), importPath, reader)); "src/qux/corge.capnp", importPath, reader));
EXPECT_EQ(0x83456789abcdef12ull, corgeSchema.getProto().getId()); EXPECT_EQ(0x83456789abcdef12ull, corgeSchema.getProto().getId());
EXPECT_EQ("qux/corge.capnp", corgeSchema.getProto().getDisplayName()); EXPECT_EQ("qux/corge.capnp", corgeSchema.getProto().getDisplayName());
auto corgeStruct = corgeSchema.getNested("Corge").asStruct(); auto corgeStruct = corgeSchema.getNested("Corge").asStruct();
EXPECT_EQ(corgeStruct, barStruct.getDependency(corgeStruct.getProto().getId())); EXPECT_EQ(corgeStruct, barStruct.getDependency(corgeStruct.getProto().getId()));
auto graultSchema = parser.parseFile(SchemaFile::newDiskFile( auto graultSchema = parser.parseFile(SchemaFile::newDiskFile(
kj::str("not/used/because/already/loaded"), "not/used/because/already/loaded",
kj::str("/usr/include/grault.capnp"), importPath, reader)); "/usr/include/grault.capnp", importPath, reader));
EXPECT_EQ(0x8456789abcdef123ull, graultSchema.getProto().getId()); EXPECT_EQ(0x8456789abcdef123ull, graultSchema.getProto().getId());
EXPECT_EQ("grault.capnp", graultSchema.getProto().getDisplayName()); EXPECT_EQ("grault.capnp", graultSchema.getProto().getDisplayName());
auto graultStruct = graultSchema.getNested("Grault").asStruct(); auto graultStruct = graultSchema.getNested("Grault").asStruct();
...@@ -136,11 +136,45 @@ TEST(SchemaParser, Basic) { ...@@ -136,11 +136,45 @@ TEST(SchemaParser, Basic) {
// Try importing the other grault.capnp directly. It'll get the display name we specify since // Try importing the other grault.capnp directly. It'll get the display name we specify since
// it wasn't imported before. // it wasn't imported before.
auto wrongGraultSchema = parser.parseFile(SchemaFile::newDiskFile( auto wrongGraultSchema = parser.parseFile(SchemaFile::newDiskFile(
kj::str("weird/display/name.capnp"), "weird/display/name.capnp",
kj::str("/opt/include/grault.capnp"), importPath, reader)); "/opt/include/grault.capnp", importPath, reader));
EXPECT_EQ(0x8000000000000001ull, wrongGraultSchema.getProto().getId()); EXPECT_EQ(0x8000000000000001ull, wrongGraultSchema.getProto().getId());
EXPECT_EQ("weird/display/name.capnp", wrongGraultSchema.getProto().getDisplayName()); EXPECT_EQ("weird/display/name.capnp", wrongGraultSchema.getProto().getDisplayName());
} }
TEST(SchemaParser, Constants) {
// This is actually a test of the full dynamic API stack for constants, because the schemas for
// constants are not actually accessible from the generated code API, so the only way to ever
// get a ConstSchema is by parsing it.
SchemaParser parser;
FakeFileReader reader;
reader.add("const.capnp",
"@0x8123456789abcdef;\n"
"const uint32Const :UInt32 = 1234;\n"
"const listConst :List(Float32) = [1.25, 2.5, 3e4];\n"
"const structConst :Foo = (bar = 123, baz = \"qux\");\n"
"struct Foo {\n"
" bar @0 :Int16;\n"
" baz @1 :Text;\n"
"}\n");
ParsedSchema barSchema = parser.parseFile(SchemaFile::newDiskFile(
"const.capnp", "const.capnp", nullptr, reader));
EXPECT_EQ(1234, barSchema.getNested("uint32Const").asConst().as<uint32_t>());
auto list = barSchema.getNested("listConst").asConst().as<DynamicList>();
ASSERT_EQ(3u, list.size());
EXPECT_EQ(1.25, list[0].as<float>());
EXPECT_EQ(2.5, list[1].as<float>());
EXPECT_EQ(3e4f, list[2].as<float>());
auto structConst = barSchema.getNested("structConst").asConst().as<DynamicStruct>();
EXPECT_EQ(123, structConst.get("bar").as<int16_t>());
EXPECT_EQ("qux", structConst.get("baz").as<Text>());
}
} // namespace } // namespace
} // namespace capnp } // namespace capnp
...@@ -77,12 +77,45 @@ InterfaceSchema Schema::asInterface() const { ...@@ -77,12 +77,45 @@ InterfaceSchema Schema::asInterface() const {
return InterfaceSchema(raw); return InterfaceSchema(raw);
} }
ConstSchema Schema::asConst() const {
KJ_REQUIRE(getProto().isConst(), "Tried to use non-constant schema as a constant.",
getProto().getDisplayName());
return ConstSchema(raw);
}
void Schema::requireUsableAs(const _::RawSchema* expected) const { void Schema::requireUsableAs(const _::RawSchema* expected) const {
KJ_REQUIRE(raw == expected || KJ_REQUIRE(raw == expected ||
(raw != nullptr && expected != nullptr && raw->canCastTo == expected), (raw != nullptr && expected != nullptr && raw->canCastTo == expected),
"This schema is not compatible with the requested native type."); "This schema is not compatible with the requested native type.");
} }
uint32_t Schema::getSchemaOffset(const schema::Value::Reader& value) const {
const word* ptr;
switch (value.which()) {
case schema::Value::TEXT:
ptr = reinterpret_cast<const word*>(value.getText().begin());
break;
case schema::Value::DATA:
ptr = reinterpret_cast<const word*>(value.getData().begin());
break;
case schema::Value::STRUCT:
ptr = value.getStruct<_::UncheckedMessage>();
break;
case schema::Value::LIST:
ptr = value.getList<_::UncheckedMessage>();
break;
case schema::Value::OBJECT:
ptr = value.getObject<_::UncheckedMessage>();
break;
default:
KJ_FAIL_ASSERT("getDefaultValueSchemaOffset() can only be called on struct, list, "
"and object fields.");
}
return ptr - raw->encodedNode;
}
// ======================================================================================= // =======================================================================================
namespace { namespace {
...@@ -156,31 +189,7 @@ kj::Maybe<StructSchema::Field> StructSchema::getFieldByDiscriminant(uint16_t dis ...@@ -156,31 +189,7 @@ kj::Maybe<StructSchema::Field> StructSchema::getFieldByDiscriminant(uint16_t dis
} }
uint32_t StructSchema::Field::getDefaultValueSchemaOffset() const { uint32_t StructSchema::Field::getDefaultValueSchemaOffset() const {
auto defaultValue = proto.getNonGroup().getDefaultValue(); return parent.getSchemaOffset(proto.getNonGroup().getDefaultValue());
const word* ptr;
switch (defaultValue.which()) {
case schema::Value::TEXT:
ptr = reinterpret_cast<const word*>(defaultValue.getText().begin());
break;
case schema::Value::DATA:
ptr = reinterpret_cast<const word*>(defaultValue.getData().begin());
break;
case schema::Value::STRUCT:
ptr = defaultValue.getStruct<_::UncheckedMessage>();
break;
case schema::Value::LIST:
ptr = defaultValue.getList<_::UncheckedMessage>();
break;
case schema::Value::OBJECT:
ptr = defaultValue.getObject<_::UncheckedMessage>();
break;
default:
KJ_FAIL_ASSERT("getDefaultValueSchemaOffset() can only be called on struct, list, "
"and object fields.");
}
return ptr - parent.raw->encodedNode;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
...@@ -219,6 +228,12 @@ InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) con ...@@ -219,6 +228,12 @@ InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) con
} }
} }
// -------------------------------------------------------------------
uint32_t ConstSchema::getValueSchemaOffset() const {
return getSchemaOffset(getProto().getConst().getValue());
}
// ======================================================================================= // =======================================================================================
ListSchema ListSchema::of(schema::Type::Which primitiveType) { ListSchema ListSchema::of(schema::Type::Which primitiveType) {
......
...@@ -32,6 +32,7 @@ class Schema; ...@@ -32,6 +32,7 @@ class Schema;
class StructSchema; class StructSchema;
class EnumSchema; class EnumSchema;
class InterfaceSchema; class InterfaceSchema;
class ConstSchema;
class ListSchema; class ListSchema;
template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; }; template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; };
...@@ -57,6 +58,8 @@ public: ...@@ -57,6 +58,8 @@ public:
// Get the Schema for a particular compiled-in type. // Get the Schema for a particular compiled-in type.
schema::Node::Reader getProto() const; schema::Node::Reader getProto() const;
// Get the underlying Cap'n Proto representation of the schema node. (Note that this accessor
// has performance comparable to accessors of struct-typed fields on Reader classes.)
kj::ArrayPtr<const word> asUncheckedMessage() const; kj::ArrayPtr<const word> asUncheckedMessage() const;
// Get the encoded schema node content as a single message segment. It is safe to read as an // Get the encoded schema node content as a single message segment. It is safe to read as an
...@@ -84,7 +87,9 @@ public: ...@@ -84,7 +87,9 @@ public:
StructSchema asStruct() const; StructSchema asStruct() const;
EnumSchema asEnum() const; EnumSchema asEnum() const;
InterfaceSchema asInterface() const; InterfaceSchema asInterface() const;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match. ConstSchema asConst() const;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match. Use
// getProto() to determine type, e.g. getProto().isStruct().
inline bool operator==(const Schema& other) const { return raw == other.raw; } inline bool operator==(const Schema& other) const { return raw == other.raw; }
inline bool operator!=(const Schema& other) const { return raw != other.raw; } inline bool operator!=(const Schema& other) const { return raw != other.raw; }
...@@ -114,9 +119,12 @@ private: ...@@ -114,9 +119,12 @@ private:
void requireUsableAs(const _::RawSchema* expected) const; void requireUsableAs(const _::RawSchema* expected) const;
uint32_t getSchemaOffset(const schema::Value::Reader& value) const;
friend class StructSchema; friend class StructSchema;
friend class EnumSchema; friend class EnumSchema;
friend class InterfaceSchema; friend class InterfaceSchema;
friend class ConstSchema;
friend class ListSchema; friend class ListSchema;
friend class SchemaLoader; friend class SchemaLoader;
}; };
...@@ -401,6 +409,32 @@ private: ...@@ -401,6 +409,32 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
class ConstSchema: public Schema {
// Represents a constant declaration.
//
// `ConstSchema` can be implicitly cast to DynamicValue to read its value.
public:
ConstSchema() = default;
template <typename T>
ReaderFor<T> as() const;
// Read the constant's value. This is a convenience method equivalent to casting the ConstSchema
// to a DynamicValue and then calling its `as<T>()` method. For dependency reasons, this method
// is defined in <capnp/dynamic.h>, which you must #include explicitly.
uint32_t getValueSchemaOffset() const;
// Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer
// type, this gets the offset from the beginning of the constant's schema node to a pointer
// representing the constant value.
private:
ConstSchema(const _::RawSchema* raw): Schema(raw) {}
friend class Schema;
};
// -------------------------------------------------------------------
class ListSchema { class ListSchema {
// ListSchema is a little different because list types are not described by schema nodes. So, // ListSchema is a little different because list types are not described by schema nodes. So,
// ListSchema doesn't subclass Schema. // ListSchema doesn't subclass Schema.
......
...@@ -267,7 +267,8 @@ kj::StringTree prettyPrint(DynamicList::Builder value) { return prettyPrint(valu ...@@ -267,7 +267,8 @@ 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::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value) { return stringify(value.asReader()); } 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(DynamicEnum value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicObject& 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::Reader& value) { return stringify(value); }
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); } kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value) { return stringify(value.asReader()); }
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value) { return stringify(value); } 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