diff src/capnproto-git-20161025/c++/src/capnp/schema.c++ @ 133:1ac99bfc383d

Add Cap'n Proto source
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 25 Oct 2016 11:17:01 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/capnproto-git-20161025/c++/src/capnp/schema.c++	Tue Oct 25 11:17:01 2016 +0100
@@ -0,0 +1,942 @@
+// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
+// Licensed under the MIT License:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "schema.h"
+#include "message.h"
+#include <kj/debug.h>
+
+namespace capnp {
+
+namespace _ {  // private
+
+// Null schemas generated using the below schema file with:
+//
+//     capnp eval -Isrc null-schemas.capnp node --flat |
+//         hexdump -v -e '8/1 "0x%02x, "' -e '1/8 "\n"'; echo
+//
+// I totally don't understand hexdump format strings and came up with this command based on trial
+// and error.
+//
+//     @0x879863d4b2cc4a1e;
+//
+//     using Node = import "/capnp/schema.capnp".Node;
+//
+//     const node :Node = (
+//         id = 0x0000000000000000,
+//         displayName = "(null schema)");
+//
+//     const struct :Node = (
+//         id = 0x0000000000000001,
+//         displayName = "(null struct schema)",
+//         struct = (
+//             dataWordCount = 0,
+//             pointerCount = 0,
+//             preferredListEncoding = empty));
+//
+//     const enum :Node = (
+//         id = 0x0000000000000002,
+//         displayName = "(null enum schema)",
+//         enum = ());
+//
+//     const interface :Node = (
+//         id = 0x0000000000000003,
+//         displayName = "(null interface schema)",
+//         interface = ());
+//
+//     const const :Node = (
+//         id = 0x0000000000000004,
+//         displayName = "(null const schema)",
+//         const = (type = (void = void), value = (void = void)));
+
+static const AlignedData<13> NULL_SCHEMA_BYTES = {{
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,   // union discriminant intentionally mangled
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x63,
+  0x68, 0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00,
+}};
+const RawSchema NULL_SCHEMA = {
+  0x0000000000000000, NULL_SCHEMA_BYTES.words, 13,
+  nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr,
+  { &NULL_SCHEMA, nullptr, nullptr, 0, 0, nullptr }
+};
+
+static const AlignedData<14> NULL_STRUCT_SCHEMA_BYTES = {{
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x74,
+  0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x63, 0x68,
+  0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00,
+}};
+const RawSchema NULL_STRUCT_SCHEMA = {
+  0x0000000000000001, NULL_STRUCT_SCHEMA_BYTES.words, 14,
+  nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr,
+  { &NULL_STRUCT_SCHEMA, nullptr, nullptr, 0, 0, nullptr }
+};
+
+static const AlignedData<14> NULL_ENUM_SCHEMA_BYTES = {{
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x65, 0x6e,
+  0x75, 0x6d, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d,
+  0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+}};
+const RawSchema NULL_ENUM_SCHEMA = {
+  0x0000000000000002, NULL_ENUM_SCHEMA_BYTES.words, 14,
+  nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr,
+  { &NULL_ENUM_SCHEMA, nullptr, nullptr, 0, 0, nullptr }
+};
+
+static const AlignedData<14> NULL_INTERFACE_SCHEMA_BYTES = {{
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x69, 0x6e,
+  0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20,
+  0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x29, 0x00,
+}};
+const RawSchema NULL_INTERFACE_SCHEMA = {
+  0x0000000000000003, NULL_INTERFACE_SCHEMA_BYTES.words, 14,
+  nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr,
+  { &NULL_INTERFACE_SCHEMA, nullptr, nullptr, 0, 0, nullptr }
+};
+
+static const AlignedData<20> NULL_CONST_SCHEMA_BYTES = {{
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+  0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x63, 0x6f,
+  0x6e, 0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65,
+  0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+}};
+const RawSchema NULL_CONST_SCHEMA = {
+  0x0000000000000004, NULL_CONST_SCHEMA_BYTES.words, 20,
+  nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr,
+  { &NULL_CONST_SCHEMA, nullptr, nullptr, 0, 0, nullptr }
+};
+
+}  // namespace _ (private)
+
+// =======================================================================================
+
+schema::Node::Reader Schema::getProto() const {
+  return readMessageUnchecked<schema::Node>(raw->generic->encodedNode);
+}
+
+kj::ArrayPtr<const word> Schema::asUncheckedMessage() const {
+  return kj::arrayPtr(raw->generic->encodedNode, raw->generic->encodedSize);
+}
+
+Schema Schema::getDependency(uint64_t id, uint location) const {
+  {
+    // Binary search dependency list.
+    uint lower = 0;
+    uint upper = raw->dependencyCount;
+
+    while (lower < upper) {
+      uint mid = (lower + upper) / 2;
+
+      auto candidate = raw->dependencies[mid];
+      if (candidate.location == location) {
+        candidate.schema->ensureInitialized();
+        return Schema(candidate.schema);
+      } else if (candidate.location < location) {
+        lower = mid + 1;
+      } else {
+        upper = mid;
+      }
+    }
+  }
+
+  {
+    uint lower = 0;
+    uint upper = raw->generic->dependencyCount;
+
+    while (lower < upper) {
+      uint mid = (lower + upper) / 2;
+
+      const _::RawSchema* candidate = raw->generic->dependencies[mid];
+
+      uint64_t candidateId = candidate->id;
+      if (candidateId == id) {
+        candidate->ensureInitialized();
+        return Schema(&candidate->defaultBrand);
+      } else if (candidateId < id) {
+        lower = mid + 1;
+      } else {
+        upper = mid;
+      }
+    }
+  }
+
+  KJ_FAIL_REQUIRE("Requested ID not found in dependency table.", kj::hex(id)) {
+    return Schema();
+  }
+}
+
+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()) {
+    return StructSchema();
+  }
+  return StructSchema(*this);
+}
+
+EnumSchema Schema::asEnum() const {
+  KJ_REQUIRE(getProto().isEnum(), "Tried to use non-enum schema as an enum.",
+             getProto().getDisplayName()) {
+    return EnumSchema();
+  }
+  return EnumSchema(*this);
+}
+
+InterfaceSchema Schema::asInterface() const {
+  KJ_REQUIRE(getProto().isInterface(), "Tried to use non-interface schema as an interface.",
+             getProto().getDisplayName()) {
+    return InterfaceSchema();
+  }
+  return InterfaceSchema(*this);
+}
+
+ConstSchema Schema::asConst() const {
+  KJ_REQUIRE(getProto().isConst(), "Tried to use non-constant schema as a constant.",
+             getProto().getDisplayName()) {
+    return ConstSchema();
+  }
+  return ConstSchema(*this);
+}
+
+kj::StringPtr Schema::getShortDisplayName() const {
+  auto proto = getProto();
+  return proto.getDisplayName().slice(proto.getDisplayNamePrefixLength());
+}
+
+void Schema::requireUsableAs(const _::RawSchema* expected) const {
+  KJ_REQUIRE(raw->generic == expected ||
+             (expected != nullptr && raw->generic->canCastTo == expected),
+             "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().getAs<_::UncheckedMessage>();
+      break;
+    case schema::Value::LIST:
+      ptr = value.getList().getAs<_::UncheckedMessage>();
+      break;
+    case schema::Value::ANY_POINTER:
+      ptr = value.getAnyPointer().getAs<_::UncheckedMessage>();
+      break;
+    default:
+      KJ_FAIL_ASSERT("getDefaultValueSchemaOffset() can only be called on struct, list, "
+                     "and any-pointer fields.");
+  }
+
+  return ptr - raw->generic->encodedNode;
+}
+
+Type Schema::getBrandBinding(uint64_t scopeId, uint index) const {
+  return getBrandArgumentsAtScope(scopeId)[index];
+}
+
+Type Schema::interpretType(schema::Type::Reader proto, uint location) const {
+  switch (proto.which()) {
+    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 proto.which();
+
+    case schema::Type::STRUCT: {
+      auto structType = proto.getStruct();
+      return getDependency(structType.getTypeId(), location).asStruct();
+    }
+
+    case schema::Type::ENUM: {
+      auto enumType = proto.getEnum();
+      return getDependency(enumType.getTypeId(), location).asEnum();
+    }
+
+    case schema::Type::INTERFACE: {
+      auto interfaceType = proto.getInterface();
+      return getDependency(interfaceType.getTypeId(), location).asInterface();
+    }
+
+    case schema::Type::LIST:
+      return ListSchema::of(interpretType(proto.getList().getElementType(), location));
+
+    case schema::Type::ANY_POINTER: {
+      auto anyPointer = proto.getAnyPointer();
+      switch (anyPointer.which()) {
+        case schema::Type::AnyPointer::UNCONSTRAINED:
+          return anyPointer.getUnconstrained().which();
+        case schema::Type::AnyPointer::PARAMETER: {
+          auto param = anyPointer.getParameter();
+          return getBrandBinding(param.getScopeId(), param.getParameterIndex());
+        }
+        case schema::Type::AnyPointer::IMPLICIT_METHOD_PARAMETER:
+          return Type(Type::ImplicitParameter {
+              anyPointer.getImplicitMethodParameter().getParameterIndex() });
+      }
+
+      KJ_UNREACHABLE;
+    }
+  }
+
+  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];
+  Type result;
+  if (binding.which == (uint)schema::Type::ANY_POINTER) {
+    if (binding.scopeId != 0) {
+      result = Type::BrandParameter { binding.scopeId, binding.paramIndex };
+    } else if (binding.isImplicitParameter) {
+      result = Type::ImplicitParameter { binding.paramIndex };
+    } else {
+      result = static_cast<schema::Type::AnyPointer::Unconstrained::Which>(binding.paramIndex);
+    }
+  } else if (binding.schema == nullptr) {
+    // Builtin / primitive type.
+    result = static_cast<schema::Type::Which>(binding.which);
+  } else {
+    binding.schema->ensureInitialized();
+    result = Type(static_cast<schema::Type::Which>(binding.which), binding.schema);
+  }
+
+  return result.wrapInList(binding.listDepth);
+}
+
+kj::StringPtr KJ_STRINGIFY(const Schema& schema) {
+  return schema.getProto().getDisplayName();
+}
+
+// =======================================================================================
+
+namespace {
+
+template <typename List>
+auto findSchemaMemberByName(const _::RawSchema* raw, kj::StringPtr name, List&& list)
+    -> kj::Maybe<decltype(list[0])> {
+  uint lower = 0;
+  uint upper = raw->memberCount;
+
+  while (lower < upper) {
+    uint mid = (lower + upper) / 2;
+
+    uint16_t memberIndex = raw->membersByName[mid];
+
+    auto candidate = list[memberIndex];
+    kj::StringPtr candidateName = candidate.getProto().getName();
+    if (candidateName == name) {
+      return candidate;
+    } else if (candidateName < name) {
+      lower = mid + 1;
+    } else {
+      upper = mid;
+    }
+  }
+
+  return nullptr;
+}
+
+}  // namespace
+
+StructSchema::FieldList StructSchema::getFields() const {
+  return FieldList(*this, getProto().getStruct().getFields());
+}
+
+StructSchema::FieldSubset StructSchema::getUnionFields() const {
+  auto proto = getProto().getStruct();
+  return FieldSubset(*this, proto.getFields(),
+                     raw->generic->membersByDiscriminant, proto.getDiscriminantCount());
+}
+
+StructSchema::FieldSubset StructSchema::getNonUnionFields() const {
+  auto proto = getProto().getStruct();
+  auto fields = proto.getFields();
+  auto offset = proto.getDiscriminantCount();
+  auto size = fields.size() - offset;
+  return FieldSubset(*this, fields, raw->generic->membersByDiscriminant + offset, size);
+}
+
+kj::Maybe<StructSchema::Field> StructSchema::findFieldByName(kj::StringPtr name) const {
+  return findSchemaMemberByName(raw->generic, name, getFields());
+}
+
+StructSchema::Field StructSchema::getFieldByName(kj::StringPtr name) const {
+  KJ_IF_MAYBE(member, findFieldByName(name)) {
+    return *member;
+  } else {
+    KJ_FAIL_REQUIRE("struct has no such member", name);
+  }
+}
+
+kj::Maybe<StructSchema::Field> StructSchema::getFieldByDiscriminant(uint16_t discriminant) const {
+  auto unionFields = getUnionFields();
+
+  if (discriminant >= unionFields.size()) {
+    return nullptr;
+  } else {
+    return unionFields[discriminant];
+  }
+}
+
+Type StructSchema::Field::getType() const {
+  auto proto = getProto();
+  uint location = _::RawBrandedSchema::makeDepLocation(_::RawBrandedSchema::DepKind::FIELD, index);
+
+  switch (proto.which()) {
+    case schema::Field::SLOT:
+      return parent.interpretType(proto.getSlot().getType(), location);
+
+    case schema::Field::GROUP:
+      return parent.getDependency(proto.getGroup().getTypeId(), location).asStruct();
+  }
+  KJ_UNREACHABLE;
+}
+
+uint32_t StructSchema::Field::getDefaultValueSchemaOffset() const {
+  return parent.getSchemaOffset(proto.getSlot().getDefaultValue());
+}
+
+kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field) {
+  return field.getProto().getName();
+}
+
+// -------------------------------------------------------------------
+
+EnumSchema::EnumerantList EnumSchema::getEnumerants() const {
+  return EnumerantList(*this, getProto().getEnum().getEnumerants());
+}
+
+kj::Maybe<EnumSchema::Enumerant> EnumSchema::findEnumerantByName(kj::StringPtr name) const {
+  return findSchemaMemberByName(raw->generic, name, getEnumerants());
+}
+
+EnumSchema::Enumerant EnumSchema::getEnumerantByName(kj::StringPtr name) const {
+  KJ_IF_MAYBE(enumerant, findEnumerantByName(name)) {
+    return *enumerant;
+  } else {
+    KJ_FAIL_REQUIRE("enum has no such enumerant", name);
+  }
+}
+
+// -------------------------------------------------------------------
+
+InterfaceSchema::MethodList InterfaceSchema::getMethods() const {
+  return MethodList(*this, getProto().getInterface().getMethods());
+}
+
+kj::Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(kj::StringPtr name) const {
+  uint counter = 0;
+  return findMethodByName(name, counter);
+}
+
+static constexpr uint MAX_SUPERCLASSES = 64;
+
+kj::Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(
+    kj::StringPtr name, uint& counter) const {
+  // Security:  Don't let someone DOS us with a dynamic schema containing cyclic inheritance.
+  KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") {
+    return nullptr;
+  }
+
+  auto result = findSchemaMemberByName(raw->generic, name, getMethods());
+
+  if (result == nullptr) {
+    // Search superclasses.
+    // TODO(perf):  This may be somewhat slow, and in the case of lots of diamond dependencies it
+    //   could get pathological.  Arguably we should generate a flat list of transitive
+    //   superclasses to search and store it in the RawSchema.  It's problematic, though, because
+    //   this means that a dynamically-loaded RawSchema cannot be correctly constructed until all
+    //   superclasses have been loaded, which imposes an ordering requirement on SchemaLoader or
+    //   requires updating subclasses whenever a new superclass is loaded.
+    auto superclasses = getProto().getInterface().getSuperclasses();
+    for (auto i: kj::indices(superclasses)) {
+      auto superclass = superclasses[i];
+      uint location = _::RawBrandedSchema::makeDepLocation(
+          _::RawBrandedSchema::DepKind::SUPERCLASS, i);
+      result = getDependency(superclass.getId(), location)
+          .asInterface().findMethodByName(name, counter);
+      if (result != nullptr) {
+        break;
+      }
+    }
+  }
+
+  return result;
+}
+
+InterfaceSchema::Method InterfaceSchema::getMethodByName(kj::StringPtr name) const {
+  KJ_IF_MAYBE(method, findMethodByName(name)) {
+    return *method;
+  } else {
+    KJ_FAIL_REQUIRE("interface has no such method", name);
+  }
+}
+
+InterfaceSchema::SuperclassList InterfaceSchema::getSuperclasses() const {
+  return SuperclassList(*this, getProto().getInterface().getSuperclasses());
+}
+
+bool InterfaceSchema::extends(InterfaceSchema other) const {
+  if (other.raw->generic == &_::NULL_INTERFACE_SCHEMA) {
+    // We consider all interfaces to extend the null schema.
+    return true;
+  }
+  uint counter = 0;
+  return extends(other, counter);
+}
+
+bool InterfaceSchema::extends(InterfaceSchema other, uint& counter) const {
+  // Security:  Don't let someone DOS us with a dynamic schema containing cyclic inheritance.
+  KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") {
+    return false;
+  }
+
+  if (other == *this) {
+    return true;
+  }
+
+  // TODO(perf):  This may be somewhat slow.  See findMethodByName() for discussion.
+  auto superclasses = getProto().getInterface().getSuperclasses();
+  for (auto i: kj::indices(superclasses)) {
+    auto superclass = superclasses[i];
+    uint location = _::RawBrandedSchema::makeDepLocation(
+        _::RawBrandedSchema::DepKind::SUPERCLASS, i);
+    if (getDependency(superclass.getId(), location).asInterface().extends(other, counter)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+kj::Maybe<InterfaceSchema> InterfaceSchema::findSuperclass(uint64_t typeId) const {
+  if (typeId == _::NULL_INTERFACE_SCHEMA.id) {
+    // We consider all interfaces to extend the null schema.
+    return InterfaceSchema();
+  }
+  uint counter = 0;
+  return findSuperclass(typeId, counter);
+}
+
+kj::Maybe<InterfaceSchema> InterfaceSchema::findSuperclass(uint64_t typeId, uint& counter) const {
+  // Security:  Don't let someone DOS us with a dynamic schema containing cyclic inheritance.
+  KJ_REQUIRE(counter++ < MAX_SUPERCLASSES, "Cyclic or absurdly-large inheritance graph detected.") {
+    return nullptr;
+  }
+
+  if (typeId == raw->generic->id) {
+    return *this;
+  }
+
+  // TODO(perf):  This may be somewhat slow.  See findMethodByName() for discussion.
+  auto superclasses = getProto().getInterface().getSuperclasses();
+  for (auto i: kj::indices(superclasses)) {
+    auto superclass = superclasses[i];
+    uint location = _::RawBrandedSchema::makeDepLocation(
+        _::RawBrandedSchema::DepKind::SUPERCLASS, i);
+    KJ_IF_MAYBE(result, getDependency(superclass.getId(), location).asInterface()
+                            .findSuperclass(typeId, counter)) {
+      return *result;
+    }
+  }
+
+  return nullptr;
+}
+
+StructSchema InterfaceSchema::Method::getParamType() const {
+  auto proto = getProto();
+  uint location = _::RawBrandedSchema::makeDepLocation(
+      _::RawBrandedSchema::DepKind::METHOD_PARAMS, ordinal);
+  return parent.getDependency(proto.getParamStructType(), location).asStruct();
+}
+
+StructSchema InterfaceSchema::Method::getResultType() const {
+  auto proto = getProto();
+  uint location = _::RawBrandedSchema::makeDepLocation(
+      _::RawBrandedSchema::DepKind::METHOD_RESULTS, ordinal);
+  return parent.getDependency(proto.getResultStructType(), location).asStruct();
+}
+
+InterfaceSchema InterfaceSchema::SuperclassList::operator[](uint index) const {
+  auto superclass = list[index];
+  uint location = _::RawBrandedSchema::makeDepLocation(
+      _::RawBrandedSchema::DepKind::SUPERCLASS, index);
+  return parent.getDependency(superclass.getId(), location).asInterface();
+}
+
+// -------------------------------------------------------------------
+
+uint32_t ConstSchema::getValueSchemaOffset() const {
+  return getSchemaOffset(getProto().getConst().getValue());
+}
+
+Type ConstSchema::getType() const {
+  return interpretType(getProto().getConst().getType(),
+      _::RawBrandedSchema::makeDepLocation(_::RawBrandedSchema::DepKind::CONST_TYPE, 0));
+}
+
+// =======================================================================================
+
+ListSchema ListSchema::of(schema::Type::Which primitiveType) {
+  switch (primitiveType) {
+    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:
+      break;
+
+    case schema::Type::STRUCT:
+    case schema::Type::ENUM:
+    case schema::Type::INTERFACE:
+    case schema::Type::LIST:
+      KJ_FAIL_REQUIRE("Must use one of the other ListSchema::of() overloads for complex types.");
+      break;
+
+    case schema::Type::ANY_POINTER:
+      KJ_FAIL_REQUIRE("List(AnyPointer) not supported.");
+      break;
+  }
+
+  return ListSchema(primitiveType);
+}
+
+ListSchema ListSchema::of(schema::Type::Reader elementType, Schema context) {
+  // This method is deprecated because it can only be implemented in terms of other deprecated
+  // methods. Temporarily disable warnings for those other deprecated methods.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+  switch (elementType.which()) {
+    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 of(elementType.which());
+
+    case schema::Type::STRUCT:
+      return of(context.getDependency(elementType.getStruct().getTypeId()).asStruct());
+
+    case schema::Type::ENUM:
+      return of(context.getDependency(elementType.getEnum().getTypeId()).asEnum());
+
+    case schema::Type::INTERFACE:
+      return of(context.getDependency(elementType.getInterface().getTypeId()).asInterface());
+
+    case schema::Type::LIST:
+      return of(of(elementType.getList().getElementType(), context));
+
+    case schema::Type::ANY_POINTER:
+      KJ_FAIL_REQUIRE("List(AnyPointer) not supported.");
+      return ListSchema();
+  }
+
+  // Unknown type is acceptable.
+  return ListSchema(elementType.which());
+#pragma GCC diagnostic pop
+}
+
+// =======================================================================================
+
+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));
+}
+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.") {
+    return ListSchema::of(schema::Type::VOID);
+  }
+  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.");
+
+  if (scopeId == 0) {
+    return nullptr;
+  } else {
+    return BrandParameter { scopeId, paramIndex };
+  }
+}
+
+kj::Maybe<Type::ImplicitParameter> Type::getImplicitParameter() const {
+  KJ_REQUIRE(isAnyPointer(),
+      "Type::getImplicitParameter() can only be called on AnyPointer types.");
+
+  if (isImplicitParam) {
+    return ImplicitParameter { paramIndex };
+  } else {
+    return nullptr;
+  }
+}
+
+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 && isImplicitParam == other.isImplicitParam &&
+          // Trying to comply with strict aliasing rules. Hopefully the compiler realizes that
+          // both branches compile to the same instructions and can optimize it away.
+          (scopeId != 0 || isImplicitParam ? paramIndex == other.paramIndex
+                                           : anyPointerKind == other.anyPointerKind);
+  }
+
+  KJ_UNREACHABLE;
+}
+
+size_t Type::hashCode() const {
+  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 (static_cast<size_t>(baseType) << 3) + listDepth;
+
+    case schema::Type::STRUCT:
+    case schema::Type::ENUM:
+    case schema::Type::INTERFACE:
+      return reinterpret_cast<size_t>(schema) + listDepth;
+
+    case schema::Type::LIST:
+      KJ_UNREACHABLE;
+
+    case schema::Type::ANY_POINTER: {
+      // Trying to comply with strict aliasing rules. Hopefully the compiler realizes that
+      // both branches compile to the same instructions and can optimize it away.
+      size_t val = scopeId != 0 || isImplicitParam ?
+          paramIndex : static_cast<uint16_t>(anyPointerKind);
+      return (val << 1 | isImplicitParam) ^ scopeId;
+    }
+  }
+
+  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.");
+
+  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