Commit 817576c6 authored by Kenton Varda's avatar Kenton Varda

Generics: C++ code generation.

Note that embedded schema structures in generated code are still incorrect.
parent 490acec8
......@@ -454,6 +454,35 @@ inline Orphan<AnyPointer> Orphan<AnyPointer>::releaseAs() {
return kj::mv(*this);
}
namespace _ { // private
// Specialize PointerHelpers for AnyPointer.
template <>
struct PointerHelpers<AnyPointer, Kind::OTHER> {
static inline AnyPointer::Reader get(PointerReader reader,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return AnyPointer::Reader(reader);
}
static inline AnyPointer::Builder get(PointerBuilder builder,
const void* defaultValue = nullptr,
uint defaultBytes = 0) {
return AnyPointer::Builder(builder);
}
static inline void set(PointerBuilder builder, AnyPointer::Reader value) {
AnyPointer::Builder(builder).set(value);
}
static inline void adopt(PointerBuilder builder, Orphan<AnyPointer>&& value) {
builder.adopt(kj::mv(value.builder));
}
static inline Orphan<AnyPointer> disown(PointerBuilder builder) {
return Orphan<AnyPointer>(builder.disown());
}
};
} // namespace _ (private)
} // namespace capnp
#endif // CAPNP_ANY_H_
......@@ -33,12 +33,14 @@ struct Data {
Data() = delete;
class Reader;
class Builder;
class Pipeline {};
};
struct Text {
Text() = delete;
class Reader;
class Builder;
class Pipeline {};
};
class Data::Reader: public kj::ArrayPtr<const byte> {
......
......@@ -767,6 +767,35 @@ TEST(Capability, KeywordMethods) {
EXPECT_TRUE(called);
}
TEST(Capability, Generics) {
kj::EventLoop loop;
kj::WaitScope waitScope(loop);
typedef test::TestGenerics<TestAllTypes>::Interface<List<uint32_t>> Interface;
Interface::Client client = nullptr;
auto request = client.callRequest();
request.setBaz("hello");
initTestMessage(request.initInnerBound().initFoo());
initTestMessage(request.initInnerUnbound().getFoo().initAs<TestAllTypes>());
auto promise = request.send().then([](capnp::Response<Interface::CallResults>&& response) {
// This doesn't actually execute; we're just checking that it compiles.
List<uint32_t>::Reader qux = response.getQux();
qux.size();
checkTestMessage(response.getGen().getFoo());
}, [](kj::Exception&& e) {});
promise.wait(waitScope);
}
TEST(Capability, Generics2) {
MallocMessageBuilder builder;
auto root = builder.getRoot<test::TestUseGenerics>();
root.initCap().setFoo(test::TestInterface::Client(nullptr));
}
} // namespace
} // namespace _
} // namespace capnp
This diff is collapsed.
......@@ -2628,30 +2628,30 @@ const ::capnp::_::RawSchema s_84e4f3f5a807605c = {
namespace capnp {
namespace compiler {
CAPNP_DEFINE_STRUCT(LocatedText);
CAPNP_DEFINE_STRUCT(LocatedInteger);
CAPNP_DEFINE_STRUCT(LocatedFloat);
CAPNP_DEFINE_STRUCT(Expression);
CAPNP_DEFINE_STRUCT(Expression::Param);
CAPNP_DEFINE_STRUCT(Expression::Application);
CAPNP_DEFINE_STRUCT(Expression::Member);
CAPNP_DEFINE_STRUCT(Declaration);
CAPNP_DEFINE_STRUCT(Declaration::BrandParameter);
CAPNP_DEFINE_STRUCT(Declaration::AnnotationApplication);
CAPNP_DEFINE_STRUCT(Declaration::AnnotationApplication::Value);
CAPNP_DEFINE_STRUCT(Declaration::ParamList);
CAPNP_DEFINE_STRUCT(Declaration::Param);
CAPNP_DEFINE_STRUCT(Declaration::Param::DefaultValue);
CAPNP_DEFINE_STRUCT(Declaration::Id);
CAPNP_DEFINE_STRUCT(Declaration::Using);
CAPNP_DEFINE_STRUCT(Declaration::Const);
CAPNP_DEFINE_STRUCT(Declaration::Field);
CAPNP_DEFINE_STRUCT(Declaration::Field::DefaultValue);
CAPNP_DEFINE_STRUCT(Declaration::Interface);
CAPNP_DEFINE_STRUCT(Declaration::Method);
CAPNP_DEFINE_STRUCT(Declaration::Method::Results);
CAPNP_DEFINE_STRUCT(Declaration::Annotation);
CAPNP_DEFINE_STRUCT(ParsedFile);
CAPNP_DEFINE_STRUCT(LocatedText, );
CAPNP_DEFINE_STRUCT(LocatedInteger, );
CAPNP_DEFINE_STRUCT(LocatedFloat, );
CAPNP_DEFINE_STRUCT(Expression, );
CAPNP_DEFINE_STRUCT(Expression::Param, );
CAPNP_DEFINE_STRUCT(Expression::Application, );
CAPNP_DEFINE_STRUCT(Expression::Member, );
CAPNP_DEFINE_STRUCT(Declaration, );
CAPNP_DEFINE_STRUCT(Declaration::BrandParameter, );
CAPNP_DEFINE_STRUCT(Declaration::AnnotationApplication, );
CAPNP_DEFINE_STRUCT(Declaration::AnnotationApplication::Value, );
CAPNP_DEFINE_STRUCT(Declaration::ParamList, );
CAPNP_DEFINE_STRUCT(Declaration::Param, );
CAPNP_DEFINE_STRUCT(Declaration::Param::DefaultValue, );
CAPNP_DEFINE_STRUCT(Declaration::Id, );
CAPNP_DEFINE_STRUCT(Declaration::Using, );
CAPNP_DEFINE_STRUCT(Declaration::Const, );
CAPNP_DEFINE_STRUCT(Declaration::Field, );
CAPNP_DEFINE_STRUCT(Declaration::Field::DefaultValue, );
CAPNP_DEFINE_STRUCT(Declaration::Interface, );
CAPNP_DEFINE_STRUCT(Declaration::Method, );
CAPNP_DEFINE_STRUCT(Declaration::Method::Results, );
CAPNP_DEFINE_STRUCT(Declaration::Annotation, );
CAPNP_DEFINE_STRUCT(ParsedFile, );
} // namespace
} // namespace
......
This diff is collapsed.
......@@ -450,10 +450,10 @@ const ::capnp::_::RawSchema s_a11f97b9d6c73dd4 = {
namespace capnp {
namespace compiler {
CAPNP_DEFINE_STRUCT(Token);
CAPNP_DEFINE_STRUCT(Statement);
CAPNP_DEFINE_STRUCT(LexedTokens);
CAPNP_DEFINE_STRUCT(LexedStatements);
CAPNP_DEFINE_STRUCT(Token, );
CAPNP_DEFINE_STRUCT(Statement, );
CAPNP_DEFINE_STRUCT(LexedTokens, );
CAPNP_DEFINE_STRUCT(LexedStatements, );
} // namespace
} // namespace
......
......@@ -137,7 +137,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(Token::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(Token::Reader reader) {
......@@ -227,7 +227,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(Token::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(Token::Builder builder) {
......@@ -287,7 +287,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(Statement::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(Statement::Reader reader) {
......@@ -345,7 +345,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(Statement::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(Statement::Builder builder) {
......@@ -390,7 +390,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(LexedTokens::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(LexedTokens::Reader reader) {
......@@ -422,7 +422,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(LexedTokens::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(LexedTokens::Builder builder) {
......@@ -467,7 +467,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(LexedStatements::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(LexedStatements::Reader reader) {
......@@ -499,7 +499,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(LexedStatements::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(LexedStatements::Builder builder) {
......
......@@ -614,6 +614,16 @@ public:
}
}
bool isGeneric() {
if (leafParamCount > 0) return true;
KJ_IF_MAYBE(p, parent) {
return p->get()->isGeneric();
} else {
return false;
}
}
kj::Own<BrandScope> push(uint64_t typeId, uint paramCount) {
return kj::refcounted<BrandScope>(kj::addRef(*this), typeId, paramCount);
}
......@@ -1325,6 +1335,8 @@ void NodeTranslator::compileNode(Declaration::Reader decl, schema::Node::Builder
}
}
builder.setIsGeneric(localBrand->isGeneric());
kj::StringPtr targetsFlagName;
switch (decl.which()) {
......@@ -1923,6 +1935,7 @@ private:
// We'll set the ID and scope ID later.
node.setDisplayName(kj::str(parent.getDisplayName(), '.', name));
node.setDisplayNamePrefixLength(node.getDisplayName().size() - name.size());
node.setIsGeneric(parent.getIsGeneric());
node.initStruct().setIsGroup(true);
// The remaining contents of node.struct will be filled in later.
......@@ -2187,6 +2200,7 @@ uint64_t NodeTranslator::compileParamList(
builder.setId(generateMethodParamsId(parent.getId(), ordinal, isResults));
builder.setDisplayName(kj::str(parent.getDisplayName(), '.', typeName));
builder.setDisplayNamePrefixLength(builder.getDisplayName().size() - typeName.size());
builder.setIsGeneric(parent.getIsGeneric());
builder.setScopeId(0); // detached struct type
builder.initStruct();
......
......@@ -1714,6 +1714,47 @@ TEST(Encoding, WholeFloatDefault) {
EXPECT_EQ(4e30f, test::TestWholeFloatDefault::BIG_CONSTANT);
}
TEST(Encoding, Generics) {
MallocMessageBuilder message;
auto root = message.initRoot<test::TestUseGenerics>();
auto reader = root.asReader();
initTestMessage(root.initBasic().initFoo());
checkTestMessage(reader.getBasic().getFoo());
initTestMessage(root.initInner().initFoo());
checkTestMessage(reader.getInner().getFoo());
root.initInner2().setBaz("foo");
EXPECT_EQ("foo", reader.getInner2().getBaz());
initTestMessage(root.getInner2().initInnerBound().initFoo());
checkTestMessage(reader.getInner2().getInnerBound().getFoo());
initTestMessage(root.getInner2().initInnerUnbound().getFoo().initAs<TestAllTypes>());
checkTestMessage(reader.getInner2().getInnerUnbound().getFoo().getAs<TestAllTypes>());
initTestMessage(root.initUnspecified().getFoo().initAs<TestAllTypes>());
checkTestMessage(reader.getUnspecified().getFoo().getAs<TestAllTypes>());
initTestMessage(root.initWrapper().initValue().initFoo());
checkTestMessage(reader.getWrapper().getValue().getFoo());
}
TEST(Encoding, GenericDefaults) {
test::TestUseGenerics::Reader reader;
EXPECT_EQ(123, reader.getDefault().getFoo().getInt16Field());
EXPECT_EQ(123, reader.getDefaultInner().getFoo().getInt16Field());
EXPECT_EQ("text", reader.getDefaultInner().getBar());
EXPECT_EQ(123, reader.getDefaultUser().getBasic().getFoo().getInt16Field());
EXPECT_EQ("text", reader.getDefaultWrapper().getValue().getFoo());
EXPECT_EQ(321, reader.getDefaultWrapper().getValue().getRev().getFoo().getInt16Field());
EXPECT_EQ("text", reader.getDefaultWrapper2().getValue().getValue().getFoo());
EXPECT_EQ(321, reader.getDefaultWrapper2().getValue()
.getValue().getRev().getFoo().getInt16Field());
}
} // namespace
} // namespace _ (private)
} // namespace capnp
......@@ -59,7 +59,19 @@ struct RawBrandedSchema {
uint8_t which; // Numeric value of one of schema::Type::Which.
uint16_t listDepth; // Number of times to wrap the base type in List().
const RawBrandedSchema* schema; // may be null
uint32_t paramIndex; // for AnyPointer, if it's a type parameter.
union {
const RawBrandedSchema* schema; // for struct, enum, interface
uint64_t scopeId; // for AnyPointer, if it's a type parameter
};
Binding() = default;
inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
: which(which), listDepth(listDepth), paramIndex(0), schema(schema) {}
inline constexpr Binding(uint8_t which, uint16_t listDepth,
uint64_t scopeId, uint32_t paramIndex)
: which(which), listDepth(listDepth), paramIndex(paramIndex), scopeId(scopeId) {}
};
struct Scope {
......@@ -69,6 +81,9 @@ struct RawBrandedSchema {
const Binding* bindings;
uint bindingCount;
// Bindings for those parameters.
bool isUnbound;
// This scope is unbound, in the sense of SchemaLoader::getUnbound().
};
const Scope* scopes;
......@@ -132,6 +147,10 @@ struct RawBrandedSchema {
const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
if (i != nullptr) i->init(this);
}
inline bool isUnbound() const;
// Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case
// binding lookups need to be handled specially.
};
struct RawSchema {
......@@ -194,6 +213,11 @@ struct RawSchema {
// bound to `AnyPointer`.
};
inline bool RawBrandedSchema::isUnbound() const {
// The unbound schema is the only one that has no scopes but is not the default schema.
return scopeCount == 0 && this != &generic->defaultBrand;
}
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, bool = false>
inline const RawSchema& rawSchema() {
return *CapnpPrivate::schema;
......@@ -315,14 +339,19 @@ inline constexpr uint sizeInWords() {
} // namespace capnp
#define CAPNP_COMMA ,
// Unfortunately needed if the `type` parameter to the macros below contains template parameters --
// all commas must be replaced with CAPNP_COMMA otherwise they will be interpreted as macro
// parameter separators! Ugh.
#define CAPNP_DECLARE_ENUM(type, id) \
template <> struct EnumInfo<type##_##id> { \
static constexpr uint64_t typeId = 0x##id; \
static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \
}
#define CAPNP_DEFINE_ENUM(type, ...) \
__VA_ARGS__ constexpr uint64_t EnumInfo<type>::typeId; \
__VA_ARGS__ constexpr ::capnp::_::RawSchema const* EnumInfo<type>::schema;
#define CAPNP_DEFINE_ENUM(type) \
constexpr uint64_t EnumInfo<type>::typeId; \
constexpr ::capnp::_::RawSchema const* EnumInfo<type>::schema
#define CAPNP_DECLARE_STRUCT(id, dataWordSize, pointerCount, preferredElementEncoding) \
struct _capnpPrivate { \
......@@ -333,11 +362,11 @@ inline constexpr uint sizeInWords() {
::capnp::_::FieldSize::preferredElementEncoding); \
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; \
}
#define CAPNP_DEFINE_STRUCT(type, ...) \
__VA_ARGS__ constexpr uint64_t type::_capnpPrivate::typeId; \
__VA_ARGS__ constexpr ::capnp::Kind type::_capnpPrivate::kind; \
__VA_ARGS__ constexpr ::capnp::_::StructSize type::_capnpPrivate::structSize; \
__VA_ARGS__ constexpr ::capnp::_::RawSchema const* type::_capnpPrivate::schema;
#define CAPNP_DEFINE_STRUCT(type, templates) \
templates constexpr uint64_t type::_capnpPrivate::typeId; \
templates constexpr ::capnp::Kind type::_capnpPrivate::kind; \
templates constexpr ::capnp::_::StructSize type::_capnpPrivate::structSize; \
templates constexpr ::capnp::_::RawSchema const* type::_capnpPrivate::schema
#define CAPNP_DECLARE_INTERFACE(id) \
struct _capnpPrivate { \
......@@ -345,9 +374,9 @@ inline constexpr uint sizeInWords() {
static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id; \
}
#define CAPNP_DEFINE_INTERFACE(type, ...) \
__VA_ARGS__ constexpr uint64_t type::_capnpPrivate::typeId; \
__VA_ARGS__ constexpr ::capnp::Kind type::_capnpPrivate::kind; \
__VA_ARGS__ constexpr ::capnp::_::RawSchema const* type::_capnpPrivate::schema;
#define CAPNP_DEFINE_INTERFACE(type, templates) \
templates constexpr uint64_t type::_capnpPrivate::typeId; \
templates constexpr ::capnp::Kind type::_capnpPrivate::kind; \
templates constexpr ::capnp::_::RawSchema const* type::_capnpPrivate::schema
#endif // CAPNP_GENERATED_HEADER_SUPPORT_H_
......@@ -168,6 +168,8 @@ struct List<T, Kind::PRIMITIVE> {
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(_::elementSizeForType<T>(), size * ELEMENTS);
......@@ -286,6 +288,8 @@ struct List<T, Kind::STRUCT> {
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initStructList(size * ELEMENTS, _::structSize<T>());
......@@ -393,6 +397,8 @@ struct List<List<T>, Kind::LIST> {
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(_::FieldSize::POINTER, size * ELEMENTS);
......@@ -487,6 +493,8 @@ struct List<T, Kind::BLOB> {
friend struct ToDynamic_;
};
class Pipeline {};
private:
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
return builder.initList(_::FieldSize::POINTER, size * ELEMENTS);
......
......@@ -331,12 +331,12 @@ namespace capnp {
namespace rpc {
namespace twoparty {
CAPNP_DEFINE_STRUCT(SturdyRefHostId);
CAPNP_DEFINE_STRUCT(ProvisionId);
CAPNP_DEFINE_STRUCT(RecipientId);
CAPNP_DEFINE_STRUCT(ThirdPartyCapId);
CAPNP_DEFINE_STRUCT(JoinKeyPart);
CAPNP_DEFINE_STRUCT(JoinResult);
CAPNP_DEFINE_STRUCT(SturdyRefHostId, );
CAPNP_DEFINE_STRUCT(ProvisionId, );
CAPNP_DEFINE_STRUCT(RecipientId, );
CAPNP_DEFINE_STRUCT(ThirdPartyCapId, );
CAPNP_DEFINE_STRUCT(JoinKeyPart, );
CAPNP_DEFINE_STRUCT(JoinResult, );
} // namespace
} // namespace
......
......@@ -121,7 +121,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(SturdyRefHostId::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(SturdyRefHostId::Reader reader) {
......@@ -149,7 +149,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(SturdyRefHostId::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(SturdyRefHostId::Builder builder) {
......@@ -193,7 +193,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(ProvisionId::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(ProvisionId::Reader reader) {
......@@ -221,7 +221,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(ProvisionId::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(ProvisionId::Builder builder) {
......@@ -263,7 +263,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(RecipientId::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(RecipientId::Reader reader) {
......@@ -288,7 +288,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(RecipientId::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(RecipientId::Builder builder) {
......@@ -330,7 +330,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(ThirdPartyCapId::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(ThirdPartyCapId::Reader reader) {
......@@ -355,7 +355,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(ThirdPartyCapId::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(ThirdPartyCapId::Builder builder) {
......@@ -403,7 +403,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(JoinKeyPart::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(JoinKeyPart::Reader reader) {
......@@ -437,7 +437,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(JoinKeyPart::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(JoinKeyPart::Builder builder) {
......@@ -486,7 +486,7 @@ private:
friend struct ::capnp::List;
friend class ::capnp::MessageBuilder;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(JoinResult::Reader reader);
friend ::kj::StringTree KJ_STRINGIFY(Reader reader);
};
inline ::kj::StringTree KJ_STRINGIFY(JoinResult::Reader reader) {
......@@ -521,7 +521,7 @@ private:
template <typename T, ::capnp::Kind k>
friend struct ::capnp::ToDynamic_;
friend class ::capnp::Orphanage;
friend ::kj::StringTree KJ_STRINGIFY(JoinResult::Builder builder);
friend ::kj::StringTree KJ_STRINGIFY(Builder builder);
};
inline ::kj::StringTree KJ_STRINGIFY(JoinResult::Builder builder) {
......
......@@ -1977,29 +1977,29 @@ CAPNP_DEFINE_ENUM(Durability_bbaeda2607b6f958);
namespace capnp {
namespace rpc {
CAPNP_DEFINE_STRUCT(Message);
CAPNP_DEFINE_STRUCT(Call);
CAPNP_DEFINE_STRUCT(Call::SendResultsTo);
CAPNP_DEFINE_STRUCT(Return);
CAPNP_DEFINE_STRUCT(Finish);
CAPNP_DEFINE_STRUCT(Resolve);
CAPNP_DEFINE_STRUCT(Release);
CAPNP_DEFINE_STRUCT(Disembargo);
CAPNP_DEFINE_STRUCT(Disembargo::Context);
CAPNP_DEFINE_STRUCT(Save);
CAPNP_DEFINE_STRUCT(Restore);
CAPNP_DEFINE_STRUCT(Delete);
CAPNP_DEFINE_STRUCT(Provide);
CAPNP_DEFINE_STRUCT(Accept);
CAPNP_DEFINE_STRUCT(Join);
CAPNP_DEFINE_STRUCT(MessageTarget);
CAPNP_DEFINE_STRUCT(Payload);
CAPNP_DEFINE_STRUCT(CapDescriptor);
CAPNP_DEFINE_STRUCT(PromisedAnswer);
CAPNP_DEFINE_STRUCT(PromisedAnswer::Op);
CAPNP_DEFINE_STRUCT(SturdyRef);
CAPNP_DEFINE_STRUCT(ThirdPartyCapDescriptor);
CAPNP_DEFINE_STRUCT(Exception);
CAPNP_DEFINE_STRUCT(Message, );
CAPNP_DEFINE_STRUCT(Call, );
CAPNP_DEFINE_STRUCT(Call::SendResultsTo, );
CAPNP_DEFINE_STRUCT(Return, );
CAPNP_DEFINE_STRUCT(Finish, );
CAPNP_DEFINE_STRUCT(Resolve, );
CAPNP_DEFINE_STRUCT(Release, );
CAPNP_DEFINE_STRUCT(Disembargo, );
CAPNP_DEFINE_STRUCT(Disembargo::Context, );
CAPNP_DEFINE_STRUCT(Save, );
CAPNP_DEFINE_STRUCT(Restore, );
CAPNP_DEFINE_STRUCT(Delete, );
CAPNP_DEFINE_STRUCT(Provide, );
CAPNP_DEFINE_STRUCT(Accept, );
CAPNP_DEFINE_STRUCT(Join, );
CAPNP_DEFINE_STRUCT(MessageTarget, );
CAPNP_DEFINE_STRUCT(Payload, );
CAPNP_DEFINE_STRUCT(CapDescriptor, );
CAPNP_DEFINE_STRUCT(PromisedAnswer, );
CAPNP_DEFINE_STRUCT(PromisedAnswer::Op, );
CAPNP_DEFINE_STRUCT(SturdyRef, );
CAPNP_DEFINE_STRUCT(ThirdPartyCapDescriptor, );
CAPNP_DEFINE_STRUCT(Exception, );
} // namespace
} // namespace
......
This diff is collapsed.
......@@ -333,10 +333,10 @@ TEST(SchemaLoader, Generics) {
StructSchema allTypes = loader.load(Schema::from<TestAllTypes>().getProto()).asStruct();
StructSchema tap = loader.load(Schema::from<test::TestAnyPointer>().getProto()).asStruct();
loader.load(Schema::from<test::TestGenerics::Inner>().getProto());
loader.load(Schema::from<test::TestGenerics::Inner2>().getProto());
loader.load(Schema::from<test::TestGenerics::Interface>().getProto());
loader.load(Schema::from<test::TestGenerics>().getProto());
loader.load(Schema::from<test::TestGenerics<>::Inner>().getProto());
loader.load(Schema::from<test::TestGenerics<>::Inner2<>>().getProto());
loader.load(Schema::from<test::TestGenerics<>::Interface<>>().getProto());
loader.load(Schema::from<test::TestGenerics<>>().getProto());
StructSchema schema = loader.load(Schema::from<test::TestUseGenerics>().getProto()).asStruct();
{
......
This diff is collapsed.
......@@ -74,14 +74,21 @@ public:
//
// `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives
// parameter bindings for the target type's brand parameters that were specified at the reference
// site. `scope` specifies the scope in which the type ID appeared -- if the target type and the
// scope share some common super-scope which is parameterized, and bindings for those parameters
// weren't specified in `brand`, they will be carried over from the scope.
// site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains
// parameter references or indicates that some parameters will be inherited, these will be
// interpreted within / inherited from `scope`.
kj::Maybe<Schema> tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(),
Schema scope = Schema()) const;
// Like get() but doesn't throw.
Schema getUnbound(uint64_t id) const;
// Gets a special version of the schema in which all brand parameters are "unbound". This means
// that if you look up a type via the Schema API, and it resolves to a brand parameter, the
// returned Type's getBrandParameter() method will return info about that parameter. Otherwise,
// normally, all brand parameters that aren't otherwise bound are assumed to simply be
// "AnyPointer".
Type getType(schema::Type::Reader type, Schema scope = Schema()) const;
// Convenience method which interprets a schema::Type to produce a Type object. Implemented in
// terms of get().
......
......@@ -240,6 +240,24 @@ Schema Schema::getDependency(uint64_t id, uint location) const {
}
}
Schema::BrandArgumentList Schema::getBrandArgumentsAtScope(uint64_t scopeId) const {
KJ_REQUIRE(getProto().getIsGeneric(), "Not a generic type.", getProto().getDisplayName());
for (auto scope: kj::range(raw->scopes, raw->scopes + raw->scopeCount)) {
if (scope->typeId == scopeId) {
// OK, this scope matches the scope we're looking for.
if (scope->isUnbound) {
return BrandArgumentList(scopeId, true);
} else {
return BrandArgumentList(scopeId, scope->bindingCount, scope->bindings);
}
}
}
// This scope is not listed in the scopes list.
return BrandArgumentList(scopeId, raw->isUnbound());
}
StructSchema Schema::asStruct() const {
KJ_REQUIRE(getProto().isStruct(), "Tried to use non-struct schema as a struct.",
getProto().getDisplayName()) {
......@@ -311,31 +329,7 @@ uint32_t Schema::getSchemaOffset(const schema::Value::Reader& value) const {
}
Type Schema::getBrandBinding(uint64_t scopeId, uint index) const {
for (auto scope: kj::range(raw->scopes, raw->scopes + raw->scopeCount)) {
if (scope->typeId == scopeId) {
// OK, this scope matches the scope we're looking for.
if (index >= scope->bindingCount) {
// Binding index out-of-range. Treat as unbound. This is important to allow new
// type parameters to be added to existing types without breaking dependent
// schemas.
break;
}
auto& binding = scope->bindings[index];
if (binding.schema == nullptr) {
// Builtin / primitive type.
return Type(static_cast<schema::Type::Which>(binding.which), binding.listDepth, Schema());
} else {
binding.schema->ensureInitialized();
return Type(static_cast<schema::Type::Which>(binding.which), binding.listDepth,
Schema(binding.schema));
}
}
}
// The variable is not bound. Assume AnyPointer.
return schema::Type::ANY_POINTER;
return getBrandArgumentsAtScope(scopeId)[index];
}
Type Schema::interpretType(schema::Type::Reader proto, uint location) const {
......@@ -392,6 +386,34 @@ Type Schema::interpretType(schema::Type::Reader proto, uint location) const {
KJ_UNREACHABLE;
}
Type Schema::BrandArgumentList::operator[](uint index) const {
if (isUnbound) {
return Type::BrandParameter { scopeId, index };
}
if (index >= size_) {
// Binding index out-of-range. Treat as AnyPointer. This is important to allow new
// type parameters to be added to existing types without breaking dependent
// schemas.
return schema::Type::ANY_POINTER;
}
auto& binding = bindings[index];
if (binding.which == (uint)schema::Type::ANY_POINTER) {
if (binding.scopeId == 0) {
return Type(schema::Type::ANY_POINTER, binding.listDepth, nullptr);
} else {
return Type::BrandParameter { binding.scopeId, binding.paramIndex };
}
} else if (binding.schema == nullptr) {
// Builtin / primitive type.
return Type(static_cast<schema::Type::Which>(binding.which), binding.listDepth, nullptr);
} else {
binding.schema->ensureInitialized();
return Type(static_cast<schema::Type::Which>(binding.which), binding.listDepth, binding.schema);
}
}
// =======================================================================================
namespace {
......@@ -736,41 +758,114 @@ ListSchema ListSchema::of(schema::Type::Reader elementType, Schema context) {
#pragma GCC diagnostic pop
}
StructSchema ListSchema::getStructElementType() const {
KJ_REQUIRE(nestingDepth == 0 && elementType == schema::Type::STRUCT,
"ListSchema::getStructElementType(): The elements are not structs.");
return elementSchema.asStruct();
}
// =======================================================================================
EnumSchema ListSchema::getEnumElementType() const {
KJ_REQUIRE(nestingDepth == 0 && elementType == schema::Type::ENUM,
"ListSchema::getEnumElementType(): The elements are not enums.");
return elementSchema.asEnum();
StructSchema Type::asStruct() const {
KJ_REQUIRE(isStruct(), "Tried to interpret a non-struct type as a struct.") {
return StructSchema();
}
KJ_ASSERT(schema != nullptr);
return StructSchema(Schema(schema));
}
InterfaceSchema ListSchema::getInterfaceElementType() const {
KJ_REQUIRE(nestingDepth == 0 && elementType == schema::Type::INTERFACE,
"ListSchema::getInterfaceElementType(): The elements are not interfaces.");
return elementSchema.asInterface();
EnumSchema Type::asEnum() const {
KJ_REQUIRE(isEnum(), "Tried to interpret a non-enum type as an enum.") {
return EnumSchema();
}
KJ_ASSERT(schema != nullptr);
return EnumSchema(Schema(schema));
}
InterfaceSchema Type::asInterface() const {
KJ_REQUIRE(isInterface(), "Tried to interpret a non-interface type as an interface.") {
return InterfaceSchema();
}
KJ_ASSERT(schema != nullptr);
return InterfaceSchema(Schema(schema));
}
ListSchema Type::asList() const {
KJ_REQUIRE(isList(), "Type::asList(): Not a list.");
Type elementType = *this;
--elementType.listDepth;
return ListSchema::of(elementType);
}
kj::Maybe<Type::BrandParameter> Type::getBrandParameter() const {
KJ_REQUIRE(isAnyPointer(), "Type::getBrandParameter() can only be called on AnyPointer types.");
ListSchema ListSchema::getListElementType() const {
KJ_REQUIRE(nestingDepth > 0,
"ListSchema::getListElementType(): The elements are not lists.");
return ListSchema(elementType, nestingDepth - 1, elementSchema);
if (scopeId == 0) {
return nullptr;
} else {
return BrandParameter { scopeId, paramIndex };
}
}
void ListSchema::requireUsableAs(ListSchema expected) const {
KJ_REQUIRE(elementType == expected.elementType && nestingDepth == expected.nestingDepth,
"This schema is not compatible with the requested native type.");
elementSchema.requireUsableAs(expected.elementSchema.raw->generic);
bool Type::operator==(const Type& other) const {
if (baseType != other.baseType || listDepth != other.listDepth) {
return false;
}
switch (baseType) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::TEXT:
case schema::Type::DATA:
return true;
case schema::Type::STRUCT:
case schema::Type::ENUM:
case schema::Type::INTERFACE:
return schema == other.schema;
case schema::Type::LIST:
KJ_UNREACHABLE;
case schema::Type::ANY_POINTER:
return scopeId == other.scopeId && (scopeId == 0 || paramIndex == other.paramIndex);
}
KJ_UNREACHABLE;
}
// =======================================================================================
void Type::requireUsableAs(Type expected) const {
KJ_REQUIRE(baseType == expected.baseType && listDepth == expected.listDepth,
"This type is not compatible with the requested native type.");
ListSchema Type::asList() const {
KJ_REQUIRE(listDepth > 0, "Type::asList(): Not a list.");
return ListSchema(baseType, listDepth - 1, schema);
switch (baseType) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::TEXT:
case schema::Type::DATA:
case schema::Type::ANY_POINTER:
break;
case schema::Type::STRUCT:
case schema::Type::ENUM:
case schema::Type::INTERFACE:
Schema(schema).requireUsableAs(expected.schema->generic);
break;
case schema::Type::LIST:
KJ_UNREACHABLE;
}
}
} // namespace capnp
......@@ -50,6 +50,10 @@ struct Node {
parameters @32 :List(Parameter);
# If this node is parameterized (generic), the list of parameters. Empty for non-generic types.
isGeneric @33 :Bool;
# True if this node is generic, meaning that it or one of its parent scopes has a non-empty
# `parameters`.
struct Parameter {
# Information about one of the node's parameters.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -517,6 +517,13 @@ struct TestGenerics(Foo, Bar) {
baz @1 :Baz;
innerBound @2 :Inner;
innerUnbound @3 :TestGenerics.Inner;
struct DeepNest(Qux) {
foo @0 :Foo;
bar @1 :Bar;
baz @2 :Baz;
qux @3 :Qux;
}
}
interface Interface(Qux) {
......@@ -556,6 +563,7 @@ struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
unspecified @3 :TestGenerics;
unspecifiedInner @4 :TestGenerics.Inner2(Text);
wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer);
cap @18 :TestGenerics(TestInterface, Text);
default @5 :TestGenerics(TestAllTypes, Text) =
(foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321))));
......
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