capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

capnpc-c++.c++ (126998B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 // This program is a code generator plugin for `capnp compile` which generates C++ code.
     23 
     24 #if _WIN32
     25 #include <kj/win32-api-version.h>
     26 #endif
     27 
     28 #include <capnp/schema.capnp.h>
     29 #include "../serialize.h"
     30 #include <kj/debug.h>
     31 #include <kj/io.h>
     32 #include <kj/string-tree.h>
     33 #include <kj/tuple.h>
     34 #include <kj/vector.h>
     35 #include <kj/filesystem.h>
     36 #include "../schema-loader.h"
     37 #include "../dynamic.h"
     38 #include <unordered_map>
     39 #include <unordered_set>
     40 #include <map>
     41 #include <set>
     42 #include <kj/main.h>
     43 #include <algorithm>
     44 #include <capnp/stream.capnp.h>
     45 
     46 #if _WIN32
     47 #include <windows.h>
     48 #include <kj/windows-sanity.h>
     49 #undef CONST
     50 #else
     51 #include <sys/time.h>
     52 #endif
     53 
     54 #if HAVE_CONFIG_H
     55 #include "config.h"
     56 #endif
     57 
     58 #ifndef VERSION
     59 #define VERSION "(unknown)"
     60 #endif
     61 
     62 namespace capnp {
     63 namespace {
     64 
     65 static constexpr uint64_t NAMESPACE_ANNOTATION_ID = 0xb9c6f99ebf805f2cull;
     66 static constexpr uint64_t NAME_ANNOTATION_ID = 0xf264a779fef191ceull;
     67 
     68 bool hasDiscriminantValue(const schema::Field::Reader& reader) {
     69   return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT;
     70 }
     71 
     72 void enumerateDeps(schema::Type::Reader type, std::set<uint64_t>& deps) {
     73   switch (type.which()) {
     74     case schema::Type::STRUCT:
     75       deps.insert(type.getStruct().getTypeId());
     76       break;
     77     case schema::Type::ENUM:
     78       deps.insert(type.getEnum().getTypeId());
     79       break;
     80     case schema::Type::INTERFACE:
     81       deps.insert(type.getInterface().getTypeId());
     82       break;
     83     case schema::Type::LIST:
     84       enumerateDeps(type.getList().getElementType(), deps);
     85       break;
     86     default:
     87       break;
     88   }
     89 }
     90 
     91 void enumerateDeps(schema::Node::Reader node, std::set<uint64_t>& deps) {
     92   switch (node.which()) {
     93     case schema::Node::STRUCT: {
     94       auto structNode = node.getStruct();
     95       for (auto field: structNode.getFields()) {
     96         switch (field.which()) {
     97           case schema::Field::SLOT:
     98             enumerateDeps(field.getSlot().getType(), deps);
     99             break;
    100           case schema::Field::GROUP:
    101             deps.insert(field.getGroup().getTypeId());
    102             break;
    103         }
    104       }
    105       if (structNode.getIsGroup()) {
    106         deps.insert(node.getScopeId());
    107       }
    108       break;
    109     }
    110     case schema::Node::INTERFACE: {
    111       auto interfaceNode = node.getInterface();
    112       for (auto superclass: interfaceNode.getSuperclasses()) {
    113         deps.insert(superclass.getId());
    114       }
    115       for (auto method: interfaceNode.getMethods()) {
    116         deps.insert(method.getParamStructType());
    117         deps.insert(method.getResultStructType());
    118       }
    119       break;
    120     }
    121     default:
    122       break;
    123   }
    124 }
    125 
    126 struct OrderByName {
    127   template <typename T>
    128   inline bool operator()(const T& a, const T& b) const {
    129     return a.getProto().getName() < b.getProto().getName();
    130   }
    131 };
    132 
    133 template <typename MemberList>
    134 kj::Array<uint> makeMembersByName(MemberList&& members) {
    135   auto sorted = KJ_MAP(member, members) { return member; };
    136   std::sort(sorted.begin(), sorted.end(), OrderByName());
    137   return KJ_MAP(member, sorted) { return member.getIndex(); };
    138 }
    139 
    140 kj::StringPtr baseName(kj::StringPtr path) {
    141   KJ_IF_MAYBE(slashPos, path.findLast('/')) {
    142     return path.slice(*slashPos + 1);
    143   } else {
    144     return path;
    145   }
    146 }
    147 
    148 kj::String safeIdentifier(kj::StringPtr identifier) {
    149   // Given a desired identifier name, munge it to make it safe for use in generated code.
    150   //
    151   // If the identifier is a keyword, this adds an underscore to the end.
    152 
    153   static const std::set<kj::StringPtr> keywords({
    154     "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break",
    155     "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "constexpr",
    156     "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast",
    157     "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto",
    158     "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq",
    159     "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register",
    160     "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert",
    161     "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true",
    162     "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
    163     "volatile", "wchar_t", "while", "xor", "xor_eq"
    164   });
    165 
    166   if (keywords.count(identifier) > 0) {
    167     return kj::str(identifier, '_');
    168   } else {
    169     return kj::heapString(identifier);
    170   }
    171 }
    172 
    173 // =======================================================================================
    174 
    175 class CppTypeName {
    176   // Used to build a C++ type name string. This is complicated in the presence of templates,
    177   // because we must add the "typename" and "template" disambiguator keywords as needed.
    178 
    179 public:
    180   inline CppTypeName(): isArgDependent(false), needsTypename(false),
    181                         hasInterfaces_(false), hasDisambiguatedTemplate_(false) {}
    182   CppTypeName(CppTypeName&& other) = default;
    183   CppTypeName(const CppTypeName& other)
    184       : name(kj::strTree(other.name.flatten())),
    185         isArgDependent(other.isArgDependent),
    186         needsTypename(other.needsTypename),
    187         hasInterfaces_(other.hasInterfaces_),
    188         hasDisambiguatedTemplate_(other.hasDisambiguatedTemplate_) {}
    189 
    190   CppTypeName& operator=(CppTypeName&& other) = default;
    191   CppTypeName& operator=(const CppTypeName& other) {
    192     name = kj::strTree(other.name.flatten());
    193     isArgDependent = other.isArgDependent;
    194     needsTypename = other.needsTypename;
    195     return *this;
    196   }
    197 
    198   static CppTypeName makeRoot() {
    199     return CppTypeName(kj::strTree(" "), false);
    200   }
    201 
    202   static CppTypeName makeNamespace(kj::StringPtr name) {
    203     return CppTypeName(kj::strTree(" ::", name), false);
    204   }
    205 
    206   static CppTypeName makeTemplateParam(kj::StringPtr name) {
    207     return CppTypeName(kj::strTree(name), true);
    208   }
    209 
    210   static CppTypeName makePrimitive(kj::StringPtr name) {
    211     return CppTypeName(kj::strTree(name), false);
    212   }
    213 
    214   void addMemberType(kj::StringPtr innerName) {
    215     // Append "::innerName" to refer to a member.
    216 
    217     name = kj::strTree(kj::mv(name), "::", innerName);
    218     needsTypename = isArgDependent;
    219   }
    220 
    221   void addMemberValue(kj::StringPtr innerName) {
    222     // Append "::innerName" to refer to a member.
    223 
    224     name = kj::strTree(kj::mv(name), "::", innerName);
    225     needsTypename = false;
    226   }
    227 
    228   bool hasDisambiguatedTemplate() {
    229     return hasDisambiguatedTemplate_;
    230   }
    231 
    232   void addMemberTemplate(kj::StringPtr innerName, kj::Array<CppTypeName>&& params) {
    233     // Append "::innerName<params, ...>".
    234     //
    235     // If necessary, add the "template" disambiguation keyword in front of `innerName`.
    236 
    237     bool parentIsArgDependent = isArgDependent;
    238     needsTypename = parentIsArgDependent;
    239     hasDisambiguatedTemplate_ = hasDisambiguatedTemplate_ || parentIsArgDependent;
    240 
    241     name = kj::strTree(kj::mv(name),
    242         parentIsArgDependent ? "::template " : "::",
    243         innerName, '<',
    244         kj::StringTree(KJ_MAP(p, params) {
    245           if (p.isArgDependent) isArgDependent = true;
    246           if (p.hasInterfaces_) hasInterfaces_ = true;
    247           if (p.hasDisambiguatedTemplate_) hasDisambiguatedTemplate_ = true;
    248           return kj::strTree(kj::mv(p));
    249         }, ", "),
    250         '>');
    251   }
    252 
    253   void setHasInterfaces() {
    254     hasInterfaces_ = true;
    255   }
    256 
    257   bool hasInterfaces() {
    258     return hasInterfaces_;
    259   }
    260 
    261   kj::StringTree strNoTypename() const & { return name.flatten(); }
    262   kj::StringTree strNoTypename() && { return kj::mv(name); }
    263   // Stringify but never prefix with `typename`. Use in contexts where `typename` is implicit.
    264 
    265 private:
    266   kj::StringTree name;
    267 
    268   bool isArgDependent;
    269   // Does the name contain any template-argument-dependent types?
    270 
    271   bool needsTypename;
    272   // Does the name require a prefix of "typename"?
    273 
    274   bool hasInterfaces_;
    275   // Does this type name refer to any interface types? If so it may need to be #ifdefed out in
    276   // lite mode.
    277 
    278   bool hasDisambiguatedTemplate_;
    279   // Whether the type name contains a template type that had to be disambiguated using the
    280   // "template" keyword, e.g. "Foo<T>::template Bar<U>".
    281   //
    282   // TODO(msvc): We only track this because MSVC seems to get confused by it in some weird cases.
    283 
    284   inline CppTypeName(kj::StringTree&& name, bool isArgDependent)
    285       : name(kj::mv(name)), isArgDependent(isArgDependent), needsTypename(false),
    286         hasInterfaces_(false), hasDisambiguatedTemplate_(false) {}
    287 
    288   friend kj::StringTree KJ_STRINGIFY(CppTypeName&& typeName);
    289   friend kj::String KJ_STRINGIFY(const CppTypeName& typeName);
    290 };
    291 
    292 kj::StringTree KJ_STRINGIFY(CppTypeName&& typeName) {
    293   if (typeName.needsTypename) {
    294     return kj::strTree("typename ", kj::mv(typeName.name));
    295   } else {
    296     return kj::mv(typeName.name);
    297   }
    298 }
    299 kj::String KJ_STRINGIFY(const CppTypeName& typeName) {
    300   if (typeName.needsTypename) {
    301     return kj::str("typename ", typeName.name);
    302   } else {
    303     return typeName.name.flatten();
    304   }
    305 }
    306 
    307 CppTypeName whichKind(Type type) {
    308   // Make a CppTypeName representing the capnp::Kind value for the given schema type. This makes
    309   // CppTypeName conflate types and values, but this is all just a hack for MSVC's benefit. Its
    310   // primary use is as a non-type template parameter to `capnp::List<T, K>` -- normally the Kind K
    311   // is deduced via SFINAE, but MSVC just can't do it in certain cases, such as when a nested type
    312   // of `capnp::List<T, K>` is the return type of a function, and the element type T is a template
    313   // instantiation.
    314 
    315   switch (type.which()) {
    316     case schema::Type::VOID: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    317 
    318     case schema::Type::BOOL: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    319     case schema::Type::INT8: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    320     case schema::Type::INT16: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    321     case schema::Type::INT32: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    322     case schema::Type::INT64: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    323     case schema::Type::UINT8: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    324     case schema::Type::UINT16: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    325     case schema::Type::UINT32: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    326     case schema::Type::UINT64: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    327     case schema::Type::FLOAT32: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    328     case schema::Type::FLOAT64: return CppTypeName::makePrimitive(" ::capnp::Kind::PRIMITIVE");
    329 
    330     case schema::Type::TEXT: return CppTypeName::makePrimitive(" ::capnp::Kind::BLOB");
    331     case schema::Type::DATA: return CppTypeName::makePrimitive(" ::capnp::Kind::BLOB");
    332 
    333     case schema::Type::ENUM: return CppTypeName::makePrimitive(" ::capnp::Kind::ENUM");
    334     case schema::Type::STRUCT: return CppTypeName::makePrimitive(" ::capnp::Kind::STRUCT");
    335     case schema::Type::INTERFACE: return CppTypeName::makePrimitive(" ::capnp::Kind::INTERFACE");
    336 
    337     case schema::Type::LIST: return CppTypeName::makePrimitive(" ::capnp::Kind::LIST");
    338     case schema::Type::ANY_POINTER: {
    339       switch (type.whichAnyPointerKind()) {
    340         case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
    341           return CppTypeName::makePrimitive(" ::capnp::Kind::INTERFACE");
    342         default:
    343           return CppTypeName::makePrimitive(" ::capnp::Kind::OTHER");
    344       }
    345     }
    346   }
    347 
    348   KJ_UNREACHABLE;
    349 }
    350 
    351 // =======================================================================================
    352 
    353 class CapnpcCppMain {
    354 public:
    355   CapnpcCppMain(kj::ProcessContext& context): context(context) {}
    356 
    357   kj::MainFunc getMain() {
    358     return kj::MainBuilder(context, "Cap'n Proto C++ plugin version " VERSION,
    359           "This is a Cap'n Proto compiler plugin which generates C++ code. "
    360           "It is meant to be run using the Cap'n Proto compiler, e.g.:\n"
    361           "    capnp compile -oc++ foo.capnp")
    362         .callAfterParsing(KJ_BIND_METHOD(*this, run))
    363         .build();
    364   }
    365 
    366 private:
    367   kj::ProcessContext& context;
    368   SchemaLoader schemaLoader;
    369   std::unordered_set<uint64_t> usedImports;
    370   bool hasInterfaces = false;
    371 
    372   CppTypeName cppFullName(Schema schema, kj::Maybe<InterfaceSchema::Method> method) {
    373     return cppFullName(schema, schema, method);
    374   }
    375 
    376   CppTypeName cppFullName(Schema schema, Schema brand, kj::Maybe<InterfaceSchema::Method> method) {
    377     auto node = schema.getProto();
    378 
    379     if (node.getScopeId() == 0) {
    380       // This is the file-level scope. Search for the namespace annotation.
    381       KJ_REQUIRE(node.isFile(),
    382           "Non-file had scopeId zero; perhaps it's a method param / result struct?");
    383       usedImports.insert(node.getId());
    384       KJ_IF_MAYBE(ns, annotationValue(node, NAMESPACE_ANNOTATION_ID)) {
    385         return CppTypeName::makeNamespace(ns->getText());
    386       } else {
    387         return CppTypeName::makeRoot();
    388       }
    389     } else {
    390       // This is a named type.
    391 
    392       // Figure out what name to use.
    393       Schema parent = schemaLoader.get(node.getScopeId());
    394       kj::StringPtr unqualifiedName;
    395       kj::String ownUnqualifiedName;
    396       KJ_IF_MAYBE(annotatedName, annotationValue(node, NAME_ANNOTATION_ID)) {
    397         // The node's name has been overridden for C++ by an annotation.
    398         unqualifiedName = annotatedName->getText();
    399       } else {
    400         // Search among the parent's nested nodes to for this node, in order to determine its name.
    401         auto parentProto = parent.getProto();
    402         for (auto nested: parentProto.getNestedNodes()) {
    403           if (nested.getId() == node.getId()) {
    404             unqualifiedName = nested.getName();
    405             break;
    406           }
    407         }
    408         if (unqualifiedName == nullptr) {
    409           // Hmm, maybe it's a group node?
    410           if (parentProto.isStruct()) {
    411             for (auto field: parentProto.getStruct().getFields()) {
    412               if (field.isGroup() && field.getGroup().getTypeId() == node.getId()) {
    413                 ownUnqualifiedName = toTitleCase(protoName(field));
    414                 unqualifiedName = ownUnqualifiedName;
    415                 break;
    416               }
    417             }
    418           }
    419         }
    420         KJ_REQUIRE(unqualifiedName != nullptr,
    421             "A schema Node's supposed scope did not contain the node as a NestedNode.");
    422       }
    423 
    424       auto result = cppFullName(parent, brand, method);
    425 
    426       // Construct the generic arguments.
    427       auto params = node.getParameters();
    428       if (params.size() > 0) {
    429         auto args = brand.getBrandArgumentsAtScope(node.getId());
    430 
    431 #if 0
    432         // Figure out exactly how many params are not bound to AnyPointer.
    433         // TODO(msvc): In a few obscure cases, MSVC does not like empty template pramater lists,
    434         //   even if all parameters have defaults. So, we give in and explicitly list all
    435         //   parameters in our generated code for now. Try again later.
    436         uint paramCount = 0;
    437         for (uint i: kj::indices(params)) {
    438           auto arg = args[i];
    439           if (arg.which() != schema::Type::ANY_POINTER || arg.getBrandParameter() != nullptr ||
    440               (arg.getImplicitParameter() != nullptr && method != nullptr)) {
    441             paramCount = i + 1;
    442           }
    443         }
    444 #else
    445         uint paramCount = params.size();
    446 #endif
    447 
    448         result.addMemberTemplate(unqualifiedName,
    449             KJ_MAP(i, kj::range(0u, paramCount)) {
    450               return typeName(args[i], method);
    451             });
    452       } else {
    453         result.addMemberType(unqualifiedName);
    454       }
    455 
    456       return result;
    457     }
    458   }
    459 
    460   kj::String toUpperCase(kj::StringPtr name) {
    461     kj::Vector<char> result(name.size() + 4);
    462 
    463     for (char c: name) {
    464       if ('a' <= c && c <= 'z') {
    465         result.add(c - 'a' + 'A');
    466       } else if (result.size() > 0 && 'A' <= c && c <= 'Z') {
    467         result.add('_');
    468         result.add(c);
    469       } else {
    470         result.add(c);
    471       }
    472     }
    473 
    474     if (result.size() == 4 && memcmp(result.begin(), "NULL", 4) == 0) {
    475       // NULL probably collides with a macro.
    476       result.add('_');
    477     }
    478 
    479     result.add('\0');
    480 
    481     return kj::String(result.releaseAsArray());
    482   }
    483 
    484   kj::String toTitleCase(kj::StringPtr name) {
    485     kj::String result = kj::heapString(name);
    486     if ('a' <= result[0] && result[0] <= 'z') {
    487       result[0] = result[0] - 'a' + 'A';
    488     }
    489     return kj::mv(result);
    490   }
    491 
    492   CppTypeName typeName(Type type, kj::Maybe<InterfaceSchema::Method> method) {
    493     switch (type.which()) {
    494       case schema::Type::VOID: return CppTypeName::makePrimitive(" ::capnp::Void");
    495 
    496       case schema::Type::BOOL: return CppTypeName::makePrimitive("bool");
    497       case schema::Type::INT8: return CppTypeName::makePrimitive(" ::int8_t");
    498       case schema::Type::INT16: return CppTypeName::makePrimitive(" ::int16_t");
    499       case schema::Type::INT32: return CppTypeName::makePrimitive(" ::int32_t");
    500       case schema::Type::INT64: return CppTypeName::makePrimitive(" ::int64_t");
    501       case schema::Type::UINT8: return CppTypeName::makePrimitive(" ::uint8_t");
    502       case schema::Type::UINT16: return CppTypeName::makePrimitive(" ::uint16_t");
    503       case schema::Type::UINT32: return CppTypeName::makePrimitive(" ::uint32_t");
    504       case schema::Type::UINT64: return CppTypeName::makePrimitive(" ::uint64_t");
    505       case schema::Type::FLOAT32: return CppTypeName::makePrimitive("float");
    506       case schema::Type::FLOAT64: return CppTypeName::makePrimitive("double");
    507 
    508       case schema::Type::TEXT: return CppTypeName::makePrimitive(" ::capnp::Text");
    509       case schema::Type::DATA: return CppTypeName::makePrimitive(" ::capnp::Data");
    510 
    511       case schema::Type::ENUM:
    512         return cppFullName(type.asEnum(), method);
    513       case schema::Type::STRUCT:
    514         return cppFullName(type.asStruct(), method);
    515       case schema::Type::INTERFACE: {
    516         auto result = cppFullName(type.asInterface(), method);
    517         result.setHasInterfaces();
    518         return result;
    519       }
    520 
    521       case schema::Type::LIST: {
    522         CppTypeName result = CppTypeName::makeNamespace("capnp");
    523         auto params = kj::heapArrayBuilder<CppTypeName>(2);
    524         auto list = type.asList();
    525         params.add(typeName(list.getElementType(), method));
    526         params.add(whichKind(list.getElementType()));
    527         result.addMemberTemplate("List", params.finish());
    528         return result;
    529       }
    530 
    531       case schema::Type::ANY_POINTER:
    532         KJ_IF_MAYBE(param, type.getBrandParameter()) {
    533           return CppTypeName::makeTemplateParam(schemaLoader.get(param->scopeId).getProto()
    534               .getParameters()[param->index].getName());
    535         } else KJ_IF_MAYBE(param, type.getImplicitParameter()) {
    536           KJ_IF_MAYBE(m, method) {
    537             auto params = m->getProto().getImplicitParameters();
    538             KJ_REQUIRE(param->index < params.size());
    539             return CppTypeName::makeTemplateParam(params[param->index].getName());
    540           } else {
    541             return CppTypeName::makePrimitive(" ::capnp::AnyPointer");
    542           }
    543         } else {
    544           switch (type.whichAnyPointerKind()) {
    545             case schema::Type::AnyPointer::Unconstrained::ANY_KIND:
    546               return CppTypeName::makePrimitive(" ::capnp::AnyPointer");
    547             case schema::Type::AnyPointer::Unconstrained::STRUCT:
    548               return CppTypeName::makePrimitive(" ::capnp::AnyStruct");
    549             case schema::Type::AnyPointer::Unconstrained::LIST:
    550               return CppTypeName::makePrimitive(" ::capnp::AnyList");
    551             case schema::Type::AnyPointer::Unconstrained::CAPABILITY: {
    552               hasInterfaces = true;  // Probably need to #include <capnp/capability.h>.
    553               auto result = CppTypeName::makePrimitive(" ::capnp::Capability");
    554               result.setHasInterfaces();
    555               return result;
    556             }
    557           }
    558           KJ_UNREACHABLE;
    559         }
    560     }
    561     KJ_UNREACHABLE;
    562   }
    563 
    564   template <typename P>
    565   kj::Maybe<schema::Value::Reader> annotationValue(P proto, uint64_t annotationId) {
    566     for (auto annotation: proto.getAnnotations()) {
    567       if (annotation.getId() == annotationId) {
    568         return annotation.getValue();
    569       }
    570     }
    571     return nullptr;
    572   }
    573 
    574   template <typename P>
    575   kj::StringPtr protoName(P proto) {
    576     KJ_IF_MAYBE(name, annotationValue(proto, NAME_ANNOTATION_ID)) {
    577       return name->getText();
    578     } else {
    579       return proto.getName();
    580     }
    581   }
    582 
    583   kj::StringTree literalValue(Type type, schema::Value::Reader value) {
    584     switch (value.which()) {
    585       case schema::Value::VOID: return kj::strTree(" ::capnp::VOID");
    586       case schema::Value::BOOL: return kj::strTree(value.getBool() ? "true" : "false");
    587       case schema::Value::INT8: return kj::strTree(value.getInt8());
    588       case schema::Value::INT16: return kj::strTree(value.getInt16());
    589       case schema::Value::INT32: return kj::strTree(value.getInt32());
    590       case schema::Value::INT64: return kj::strTree(value.getInt64(), "ll");
    591       case schema::Value::UINT8: return kj::strTree(value.getUint8(), "u");
    592       case schema::Value::UINT16: return kj::strTree(value.getUint16(), "u");
    593       case schema::Value::UINT32: return kj::strTree(value.getUint32(), "u");
    594       case schema::Value::UINT64: return kj::strTree(value.getUint64(), "llu");
    595       case schema::Value::FLOAT32: {
    596         auto text = kj::str(value.getFloat32());
    597         if (text.findFirst('.') == nullptr &&
    598             text.findFirst('e') == nullptr &&
    599             text.findFirst('E') == nullptr) {
    600           text = kj::str(text, ".0");
    601         }
    602         return kj::strTree(kj::mv(text), "f");
    603       }
    604       case schema::Value::FLOAT64: return kj::strTree(value.getFloat64());
    605       case schema::Value::ENUM: {
    606         EnumSchema schema = type.asEnum();
    607         if (value.getEnum() < schema.getEnumerants().size()) {
    608           return kj::strTree(
    609               cppFullName(schema, nullptr), "::",
    610               toUpperCase(protoName(schema.getEnumerants()[value.getEnum()].getProto())));
    611         } else {
    612           return kj::strTree("static_cast<", cppFullName(schema, nullptr),
    613                              ">(", value.getEnum(), ")");
    614         }
    615       }
    616 
    617       case schema::Value::TEXT:
    618       case schema::Value::DATA:
    619       case schema::Value::STRUCT:
    620       case schema::Value::INTERFACE:
    621       case schema::Value::LIST:
    622       case schema::Value::ANY_POINTER:
    623         KJ_FAIL_REQUIRE("literalValue() can only be used on primitive types.");
    624     }
    625     KJ_UNREACHABLE;
    626   }
    627 
    628   // -----------------------------------------------------------------
    629 
    630   class TemplateContext {
    631   public:
    632     TemplateContext(): parent(nullptr) {}
    633     explicit TemplateContext(schema::Node::Reader node)
    634         : parent(nullptr), node(node) {}
    635     TemplateContext(const TemplateContext& parent, kj::StringPtr name, schema::Node::Reader node)
    636         : parent(parent), name(name), node(node) {}
    637 
    638     bool hasParams() const {
    639       return node.getParameters().size() > 0;
    640     }
    641     bool isGeneric() const {
    642       return node.getIsGeneric();
    643     }
    644     kj::Maybe<const TemplateContext&> getParent() const {
    645       return parent;
    646     }
    647     kj::StringPtr getName() const { return name; }
    648 
    649     kj::StringTree decl(bool withDefaults, kj::StringPtr suffix = nullptr) const {
    650       // "template <typename T, typename U>" for this type. Includes default assignments
    651       // ("= ::capnp::AnyPointer") if `withDefaults` is true. Returns empty string if this type
    652       // is not parameterized.
    653 
    654       auto params = node.getParameters();
    655 
    656       if (params.size() == 0) {
    657         return kj::strTree();
    658       } else {
    659         return kj::strTree(
    660             "template <", kj::StringTree(KJ_MAP(p, params) {
    661               return kj::strTree("typename ", p.getName(), suffix,
    662                   withDefaults ? " = ::capnp::AnyPointer" : "");
    663             }, ", "), ">\n");
    664       }
    665     }
    666 
    667     kj::StringTree allDecls() const {
    668       // Decl for each generic parent plus this type, one per line.
    669       return kj::strTree(parentDecls(), decl(false));
    670     }
    671 
    672     kj::StringTree parentDecls() const {
    673       // Decls just for the parents.
    674       KJ_IF_MAYBE(p, parent) {
    675         return p->allDecls();
    676       } else {
    677         return kj::strTree();
    678       }
    679     }
    680 
    681     kj::StringTree args(kj::StringPtr suffix = nullptr) const {
    682       // "<T, U>" for this type.
    683       auto params = node.getParameters();
    684 
    685       if (params.size() == 0) {
    686         return kj::strTree();
    687       } else {
    688         return kj::strTree(
    689             "<", kj::StringTree(KJ_MAP(p, params) {
    690               return kj::strTree(p.getName(), suffix);
    691             }, ", "), ">");
    692       }
    693     }
    694 
    695     kj::StringTree allArgs() const {
    696       // "S, T, U, V" -- listing all args for all enclosing scopes starting from the outermost.
    697 
    698       auto params = node.getParameters();
    699 
    700       kj::StringTree self(KJ_MAP(p, params) { return kj::strTree(p.getName()); }, ", ");
    701       kj::StringTree up;
    702       KJ_IF_MAYBE(p, parent) {
    703         up = p->allArgs();
    704       }
    705 
    706       if (self.size() == 0) {
    707         return up;
    708       } else if (up.size() == 0) {
    709         return self;
    710       } else {
    711         return kj::strTree(kj::mv(up), ", ", kj::mv(self));
    712       }
    713     }
    714 
    715     std::map<uint64_t, List<schema::Node::Parameter>::Reader> getScopeMap() const {
    716       std::map<uint64_t, List<schema::Node::Parameter>::Reader> result;
    717       const TemplateContext* current = this;
    718       for (;;) {
    719         auto params = current->node.getParameters();
    720         if (params.size() > 0) {
    721           result[current->node.getId()] = params;
    722         }
    723         KJ_IF_MAYBE(p, current->parent) {
    724           current = p;
    725         } else {
    726           return result;
    727         }
    728       }
    729     }
    730 
    731   private:
    732     kj::Maybe<const TemplateContext&> parent;
    733     kj::StringPtr name;
    734     schema::Node::Reader node;
    735   };
    736 
    737   struct BrandInitializerText {
    738     kj::StringTree scopes;
    739     kj::StringTree bindings;
    740     kj::StringTree dependencies;
    741     size_t dependencyCount;
    742     // TODO(msvc):  `dependencyCount` is the number of individual dependency definitions in
    743     //   `dependencies`. It's a hack to allow makeGenericDefinitions to hard-code the size of the
    744     //   `_capnpPrivate::brandDependencies` array into the definition of
    745     //   `_capnpPrivate::specificBrand::dependencyCount`. This is necessary because MSVC cannot
    746     //   deduce the size of `brandDependencies` if it is nested under a class template. It's
    747     //   probably this demoralizingly deferred bug:
    748     //   https://connect.microsoft.com/VisualStudio/feedback/details/759407/can-not-get-size-of-static-array-defined-in-class-template
    749   };
    750 
    751   BrandInitializerText makeBrandInitializers(
    752       const TemplateContext& templateContext, Schema schema) {
    753     auto scopeMap = templateContext.getScopeMap();
    754 
    755     auto scopes = kj::heapArrayBuilder<kj::StringTree>(scopeMap.size());
    756     kj::Vector<kj::StringTree> bindings(scopeMap.size() * 2);  // (estimate two params per scope)
    757 
    758     for (auto& scope: scopeMap) {
    759       scopes.add(kj::strTree("  { ",
    760         "0x", kj::hex(scope.first), ", "
    761         "brandBindings + ", bindings.size(), ", ",
    762         scope.second.size(), ", "
    763         "false"
    764       "},\n"));
    765 
    766       for (auto param: scope.second) {
    767         bindings.add(kj::strTree("  ::capnp::_::brandBindingFor<", param.getName(), ">(),\n"));
    768       }
    769     }
    770 
    771     auto depMap = makeBrandDepMap(templateContext, schema);
    772     auto dependencyCount = depMap.size();
    773     return {
    774       kj::strTree("{\n", scopes.finish(), "}"),
    775       kj::strTree("{\n", bindings.releaseAsArray(), "}"),
    776       makeBrandDepInitializers(kj::mv(depMap)),
    777       dependencyCount
    778     };
    779   }
    780 
    781   std::map<uint, kj::StringTree>
    782   makeBrandDepMap(const TemplateContext& templateContext, Schema schema) {
    783     // Build deps. This is separate from makeBrandDepInitializers to give calling code the
    784     // opportunity to count the number of dependencies, to calculate array sizes.
    785     std::map<uint, kj::StringTree> depMap;
    786 
    787 #define ADD_DEP(kind, index, ...) \
    788     { \
    789       uint location = _::RawBrandedSchema::makeDepLocation( \
    790           _::RawBrandedSchema::DepKind::kind, index); \
    791       KJ_IF_MAYBE(dep, makeBrandDepInitializer(__VA_ARGS__)) { \
    792         depMap[location] = kj::mv(*dep); \
    793       } \
    794     }
    795 
    796     switch (schema.getProto().which()) {
    797       case schema::Node::FILE:
    798       case schema::Node::ENUM:
    799       case schema::Node::ANNOTATION:
    800         break;
    801 
    802       case schema::Node::STRUCT:
    803         for (auto field: schema.asStruct().getFields()) {
    804           ADD_DEP(FIELD, field.getIndex(), field.getType());
    805         }
    806         break;
    807       case schema::Node::INTERFACE: {
    808         auto interface = schema.asInterface();
    809         auto superclasses = interface.getSuperclasses();
    810         for (auto i: kj::indices(superclasses)) {
    811           ADD_DEP(SUPERCLASS, i, superclasses[i]);
    812         }
    813         auto methods = interface.getMethods();
    814         for (auto i: kj::indices(methods)) {
    815           auto method = methods[i];
    816           ADD_DEP(METHOD_PARAMS, i, method, method.getParamType(), "Params");
    817           ADD_DEP(METHOD_RESULTS, i, method, method.getResultType(), "Results");
    818         }
    819         break;
    820       }
    821       case schema::Node::CONST:
    822         ADD_DEP(CONST_TYPE, 0, schema.asConst().getType());
    823         break;
    824     }
    825 #undef ADD_DEP
    826     return depMap;
    827   }
    828 
    829   kj::StringTree makeBrandDepInitializers(std::map<uint, kj::StringTree>&& depMap) {
    830     // Process depMap. Returns a braced initialiser list, or an empty string if there are no
    831     // dependencies.
    832     if (!depMap.size()) {
    833       return kj::strTree();
    834     }
    835 
    836     auto deps = kj::heapArrayBuilder<kj::StringTree>(depMap.size());
    837     for (auto& entry: depMap) {
    838       deps.add(kj::strTree("  { ", entry.first, ", ", kj::mv(entry.second), " },\n"));
    839     }
    840 
    841     return kj::strTree("{\n", kj::StringTree(deps.finish(), ""), "}");
    842   }
    843 
    844   kj::Maybe<kj::StringTree> makeBrandDepInitializer(Schema type) {
    845     // Be careful not to invoke cppFullName() if it would just be thrown away, as doing so will
    846     // add the type's declaring file to `usedImports`. In particular, this causes `stream.capnp.h`
    847     // to be #included unnecessarily.
    848     if (type.isBranded()) {
    849       return makeBrandDepInitializer(type, cppFullName(type, nullptr));
    850     } else {
    851       return nullptr;
    852     }
    853   }
    854 
    855   kj::Maybe<kj::StringTree> makeBrandDepInitializer(
    856       InterfaceSchema::Method method, StructSchema type, kj::StringPtr suffix) {
    857     auto typeProto = type.getProto();
    858     if (typeProto.getScopeId() == 0) {
    859       // This is an auto-generated params or results type.
    860       auto name = cppFullName(method.getContainingInterface(), nullptr);
    861       auto memberTypeName = kj::str(toTitleCase(protoName(method.getProto())), suffix);
    862 
    863       if (typeProto.getParameters().size() == 0) {
    864         name.addMemberType(memberTypeName);
    865       } else {
    866         // The method has implicit parameters (i.e. it's generic). For the purpose of the brand
    867         // dep initializer, we only want to supply the default AnyPointer variant, so just don't
    868         // pass any parameters here.
    869         name.addMemberTemplate(memberTypeName, nullptr);
    870       }
    871       return makeBrandDepInitializer(type, kj::mv(name));
    872     } else {
    873       return makeBrandDepInitializer(type);
    874     }
    875   }
    876 
    877   kj::Maybe<kj::StringTree> makeBrandDepInitializer(Schema type, CppTypeName name) {
    878     if (type.isBranded()) {
    879       name.addMemberType("_capnpPrivate");
    880       name.addMemberValue("brand");
    881       return kj::strTree(name, "()");
    882     } else {
    883       return nullptr;
    884     }
    885   }
    886 
    887   kj::Maybe<kj::StringTree> makeBrandDepInitializer(Type type) {
    888     switch (type.which()) {
    889       case schema::Type::VOID:
    890       case schema::Type::BOOL:
    891       case schema::Type::INT8:
    892       case schema::Type::INT16:
    893       case schema::Type::INT32:
    894       case schema::Type::INT64:
    895       case schema::Type::UINT8:
    896       case schema::Type::UINT16:
    897       case schema::Type::UINT32:
    898       case schema::Type::UINT64:
    899       case schema::Type::FLOAT32:
    900       case schema::Type::FLOAT64:
    901       case schema::Type::TEXT:
    902       case schema::Type::DATA:
    903       case schema::Type::ENUM:
    904       case schema::Type::ANY_POINTER:
    905         return nullptr;
    906 
    907       case schema::Type::STRUCT:
    908         return makeBrandDepInitializer(type.asStruct());
    909       case schema::Type::INTERFACE:
    910         return makeBrandDepInitializer(type.asInterface());
    911       case schema::Type::LIST:
    912         return makeBrandDepInitializer(type.asList().getElementType());
    913     }
    914 
    915     KJ_UNREACHABLE;
    916   }
    917 
    918   // -----------------------------------------------------------------
    919   // Code to deal with "slots" -- determines what to zero out when we clear a group.
    920 
    921   static uint typeSizeBits(schema::Type::Which whichType) {
    922     switch (whichType) {
    923       case schema::Type::BOOL: return 1;
    924       case schema::Type::INT8: return 8;
    925       case schema::Type::INT16: return 16;
    926       case schema::Type::INT32: return 32;
    927       case schema::Type::INT64: return 64;
    928       case schema::Type::UINT8: return 8;
    929       case schema::Type::UINT16: return 16;
    930       case schema::Type::UINT32: return 32;
    931       case schema::Type::UINT64: return 64;
    932       case schema::Type::FLOAT32: return 32;
    933       case schema::Type::FLOAT64: return 64;
    934       case schema::Type::ENUM: return 16;
    935 
    936       case schema::Type::VOID:
    937       case schema::Type::TEXT:
    938       case schema::Type::DATA:
    939       case schema::Type::LIST:
    940       case schema::Type::STRUCT:
    941       case schema::Type::INTERFACE:
    942       case schema::Type::ANY_POINTER:
    943         KJ_FAIL_REQUIRE("Should only be called for data types.");
    944     }
    945     KJ_UNREACHABLE;
    946   }
    947 
    948   enum class Section {
    949     NONE,
    950     DATA,
    951     POINTERS
    952   };
    953 
    954   static Section sectionFor(schema::Type::Which whichType) {
    955     switch (whichType) {
    956       case schema::Type::VOID:
    957         return Section::NONE;
    958       case schema::Type::BOOL:
    959       case schema::Type::INT8:
    960       case schema::Type::INT16:
    961       case schema::Type::INT32:
    962       case schema::Type::INT64:
    963       case schema::Type::UINT8:
    964       case schema::Type::UINT16:
    965       case schema::Type::UINT32:
    966       case schema::Type::UINT64:
    967       case schema::Type::FLOAT32:
    968       case schema::Type::FLOAT64:
    969       case schema::Type::ENUM:
    970         return Section::DATA;
    971       case schema::Type::TEXT:
    972       case schema::Type::DATA:
    973       case schema::Type::LIST:
    974       case schema::Type::STRUCT:
    975       case schema::Type::INTERFACE:
    976       case schema::Type::ANY_POINTER:
    977         return Section::POINTERS;
    978     }
    979     KJ_UNREACHABLE;
    980   }
    981 
    982   static kj::StringPtr maskType(schema::Type::Which whichType) {
    983     switch (whichType) {
    984       case schema::Type::BOOL: return "bool";
    985       case schema::Type::INT8: return " ::uint8_t";
    986       case schema::Type::INT16: return " ::uint16_t";
    987       case schema::Type::INT32: return " ::uint32_t";
    988       case schema::Type::INT64: return " ::uint64_t";
    989       case schema::Type::UINT8: return " ::uint8_t";
    990       case schema::Type::UINT16: return " ::uint16_t";
    991       case schema::Type::UINT32: return " ::uint32_t";
    992       case schema::Type::UINT64: return " ::uint64_t";
    993       case schema::Type::FLOAT32: return " ::uint32_t";
    994       case schema::Type::FLOAT64: return " ::uint64_t";
    995       case schema::Type::ENUM: return " ::uint16_t";
    996 
    997       case schema::Type::VOID:
    998       case schema::Type::TEXT:
    999       case schema::Type::DATA:
   1000       case schema::Type::LIST:
   1001       case schema::Type::STRUCT:
   1002       case schema::Type::INTERFACE:
   1003       case schema::Type::ANY_POINTER:
   1004         KJ_FAIL_REQUIRE("Should only be called for data types.");
   1005     }
   1006     KJ_UNREACHABLE;
   1007   }
   1008 
   1009   struct Slot {
   1010     schema::Type::Which whichType;
   1011     uint offset;
   1012 
   1013     bool isSupersetOf(Slot other) const {
   1014       auto section = sectionFor(whichType);
   1015       if (section != sectionFor(other.whichType)) return false;
   1016       switch (section) {
   1017         case Section::NONE:
   1018           return true;  // all voids overlap
   1019         case Section::DATA: {
   1020           auto bits = typeSizeBits(whichType);
   1021           auto start = offset * bits;
   1022           auto otherBits = typeSizeBits(other.whichType);
   1023           auto otherStart = other.offset * otherBits;
   1024           return start <= otherStart && otherStart + otherBits <= start + bits;
   1025         }
   1026         case Section::POINTERS:
   1027           return offset == other.offset;
   1028       }
   1029       KJ_UNREACHABLE;
   1030     }
   1031 
   1032     bool operator<(Slot other) const {
   1033       // Sort by section, then start position, and finally size.
   1034 
   1035       auto section = sectionFor(whichType);
   1036       auto otherSection = sectionFor(other.whichType);
   1037       if (section < otherSection) {
   1038         return true;
   1039       } else if (section > otherSection) {
   1040         return false;
   1041       }
   1042 
   1043       switch (section) {
   1044         case Section::NONE:
   1045           return false;
   1046         case Section::DATA: {
   1047           auto bits = typeSizeBits(whichType);
   1048           auto start = offset * bits;
   1049           auto otherBits = typeSizeBits(other.whichType);
   1050           auto otherStart = other.offset * otherBits;
   1051           if (start < otherStart) {
   1052             return true;
   1053           } else if (start > otherStart) {
   1054             return false;
   1055           }
   1056 
   1057           // Sort larger sizes before smaller.
   1058           return bits > otherBits;
   1059         }
   1060         case Section::POINTERS:
   1061           return offset < other.offset;
   1062       }
   1063       KJ_UNREACHABLE;
   1064     }
   1065   };
   1066 
   1067   void getSlots(StructSchema schema, kj::Vector<Slot>& slots) {
   1068     auto structProto = schema.getProto().getStruct();
   1069     if (structProto.getDiscriminantCount() > 0) {
   1070       slots.add(Slot { schema::Type::UINT16, structProto.getDiscriminantOffset() });
   1071     }
   1072 
   1073     for (auto field: schema.getFields()) {
   1074       auto proto = field.getProto();
   1075       switch (proto.which()) {
   1076         case schema::Field::SLOT: {
   1077           auto slot = proto.getSlot();
   1078           slots.add(Slot { slot.getType().which(), slot.getOffset() });
   1079           break;
   1080         }
   1081         case schema::Field::GROUP:
   1082           getSlots(field.getType().asStruct(), slots);
   1083           break;
   1084       }
   1085     }
   1086   }
   1087 
   1088   kj::Array<Slot> getSortedSlots(StructSchema schema) {
   1089     // Get a representation of all of the field locations owned by this schema, e.g. so that they
   1090     // can be zero'd out.
   1091 
   1092     kj::Vector<Slot> slots(schema.getFields().size());
   1093     getSlots(schema, slots);
   1094     std::sort(slots.begin(), slots.end());
   1095 
   1096     kj::Vector<Slot> result(slots.size());
   1097 
   1098     // All void slots are redundant, and they sort towards the front of the list.  By starting out
   1099     // with `prevSlot` = void, we will end up skipping them all, which is what we want.
   1100     Slot prevSlot = { schema::Type::VOID, 0 };
   1101     for (auto slot: slots) {
   1102       if (prevSlot.isSupersetOf(slot)) {
   1103         // This slot is redundant as prevSlot is a superset of it.
   1104         continue;
   1105       }
   1106 
   1107       // Since all sizes are power-of-two, if two slots overlap at all, one must be a superset of
   1108       // the other.  Since we sort slots by starting position, we know that the only way `slot`
   1109       // could be a superset of `prevSlot` is if they have the same starting position.  However,
   1110       // since we sort slots with the same starting position by descending size, this is not
   1111       // possible.
   1112       KJ_DASSERT(!slot.isSupersetOf(prevSlot));
   1113 
   1114       result.add(slot);
   1115 
   1116       prevSlot = slot;
   1117     }
   1118 
   1119     return result.releaseAsArray();
   1120   }
   1121 
   1122   // -----------------------------------------------------------------
   1123 
   1124   struct DiscriminantChecks {
   1125     kj::String has;
   1126     kj::String check;
   1127     kj::String set;
   1128     kj::StringTree readerIsDecl;
   1129     kj::StringTree builderIsDecl;
   1130     kj::StringTree isDefs;
   1131   };
   1132 
   1133   DiscriminantChecks makeDiscriminantChecks(kj::StringPtr scope,
   1134                                             kj::StringPtr memberName,
   1135                                             StructSchema containingStruct,
   1136                                             const TemplateContext& templateContext) {
   1137     auto discrimOffset = containingStruct.getProto().getStruct().getDiscriminantOffset();
   1138 
   1139     kj::String titleCase = toTitleCase(memberName);
   1140     kj::String upperCase = toUpperCase(memberName);
   1141 
   1142     return DiscriminantChecks {
   1143         kj::str(
   1144             "  if (which() != ", scope, upperCase, ") return false;\n"),
   1145         kj::str(
   1146             // Extra parens around the condition are needed for when we're compiling a multi-arg
   1147             // generic type, which will have a comma, which would otherwise mess up the macro.
   1148             // Ah, C++.
   1149             "  KJ_IREQUIRE((which() == ", scope, upperCase, "),\n"
   1150             "              \"Must check which() before get()ing a union member.\");\n"),
   1151         kj::str(
   1152             "  _builder.setDataField<", scope, "Which>(\n"
   1153             "      ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS, ",
   1154                       scope, upperCase, ");\n"),
   1155         kj::strTree("  inline bool is", titleCase, "() const;\n"),
   1156         kj::strTree("  inline bool is", titleCase, "();\n"),
   1157         kj::strTree(
   1158             templateContext.allDecls(),
   1159             "inline bool ", scope, "Reader::is", titleCase, "() const {\n"
   1160             "  return which() == ", scope, upperCase, ";\n"
   1161             "}\n",
   1162             templateContext.allDecls(),
   1163             "inline bool ", scope, "Builder::is", titleCase, "() {\n"
   1164             "  return which() == ", scope, upperCase, ";\n"
   1165             "}\n")
   1166     };
   1167   }
   1168 
   1169   // -----------------------------------------------------------------
   1170 
   1171   struct FieldText {
   1172     kj::StringTree readerMethodDecls;
   1173     kj::StringTree builderMethodDecls;
   1174     kj::StringTree pipelineMethodDecls;
   1175     kj::StringTree inlineMethodDefs;
   1176   };
   1177 
   1178   enum class FieldKind {
   1179     PRIMITIVE,
   1180     BLOB,
   1181     STRUCT,
   1182     LIST,
   1183     INTERFACE,
   1184     ANY_POINTER,
   1185     BRAND_PARAMETER
   1186   };
   1187 
   1188   FieldText makeFieldText(kj::StringPtr scope, StructSchema::Field field,
   1189                           const TemplateContext& templateContext) {
   1190     auto proto = field.getProto();
   1191     auto typeSchema = field.getType();
   1192     auto baseName = protoName(proto);
   1193     kj::String titleCase = toTitleCase(baseName);
   1194 
   1195     DiscriminantChecks unionDiscrim;
   1196     if (hasDiscriminantValue(proto)) {
   1197       unionDiscrim = makeDiscriminantChecks(scope, baseName, field.getContainingStruct(),
   1198                                             templateContext);
   1199     }
   1200 
   1201     switch (proto.which()) {
   1202       case schema::Field::SLOT:
   1203         // Continue below.
   1204         break;
   1205 
   1206       case schema::Field::GROUP: {
   1207         auto slots = getSortedSlots(field.getType().asStruct());
   1208         return FieldText {
   1209             kj::strTree(
   1210                 kj::mv(unionDiscrim.readerIsDecl),
   1211                 "  inline typename ", titleCase, "::Reader get", titleCase, "() const;\n"
   1212                 "\n"),
   1213 
   1214             kj::strTree(
   1215                 kj::mv(unionDiscrim.builderIsDecl),
   1216                 "  inline typename ", titleCase, "::Builder get", titleCase, "();\n"
   1217                 "  inline typename ", titleCase, "::Builder init", titleCase, "();\n"
   1218                 "\n"),
   1219 
   1220             hasDiscriminantValue(proto) ? kj::strTree() :
   1221                 kj::strTree("  inline typename ", titleCase, "::Pipeline get", titleCase, "();\n"),
   1222 
   1223             kj::strTree(
   1224                 kj::mv(unionDiscrim.isDefs),
   1225                 templateContext.allDecls(),
   1226                 "inline typename ", scope, titleCase, "::Reader ", scope, "Reader::get", titleCase, "() const {\n",
   1227                 unionDiscrim.check,
   1228                 "  return typename ", scope, titleCase, "::Reader(_reader);\n"
   1229                 "}\n",
   1230                 templateContext.allDecls(),
   1231                 "inline typename ", scope, titleCase, "::Builder ", scope, "Builder::get", titleCase, "() {\n",
   1232                 unionDiscrim.check,
   1233                 "  return typename ", scope, titleCase, "::Builder(_builder);\n"
   1234                 "}\n",
   1235                 hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree(
   1236                   "#if !CAPNP_LITE\n",
   1237                   templateContext.allDecls(),
   1238                   "inline typename ", scope, titleCase, "::Pipeline ", scope, "Pipeline::get", titleCase, "() {\n",
   1239                   "  return typename ", scope, titleCase, "::Pipeline(_typeless.noop());\n"
   1240                   "}\n"
   1241                   "#endif  // !CAPNP_LITE\n"),
   1242                 templateContext.allDecls(),
   1243                 "inline typename ", scope, titleCase, "::Builder ", scope, "Builder::init", titleCase, "() {\n",
   1244                 unionDiscrim.set,
   1245                 KJ_MAP(slot, slots) {
   1246                   switch (sectionFor(slot.whichType)) {
   1247                     case Section::NONE:
   1248                       return kj::strTree();
   1249                     case Section::DATA:
   1250                       return kj::strTree(
   1251                           "  _builder.setDataField<", maskType(slot.whichType), ">(::capnp::bounded<",
   1252                               slot.offset, ">() * ::capnp::ELEMENTS, 0);\n");
   1253                     case Section::POINTERS:
   1254                       return kj::strTree(
   1255                           "  _builder.getPointerField(::capnp::bounded<", slot.offset,
   1256                               ">() * ::capnp::POINTERS).clear();\n");
   1257                   }
   1258                   KJ_UNREACHABLE;
   1259                 },
   1260                 "  return typename ", scope, titleCase, "::Builder(_builder);\n"
   1261                 "}\n")
   1262           };
   1263       }
   1264     }
   1265 
   1266     auto slot = proto.getSlot();
   1267 
   1268     FieldKind kind = FieldKind::PRIMITIVE;
   1269     kj::String ownedType;
   1270     CppTypeName type = typeName(typeSchema, nullptr);
   1271     kj::StringPtr setterDefault;  // only for void
   1272     kj::String defaultMask;    // primitives only
   1273     size_t defaultOffset = 0;    // pointers only: offset of the default value within the schema.
   1274     size_t defaultSize = 0;      // blobs only: byte size of the default value.
   1275 
   1276     auto defaultBody = slot.getDefaultValue();
   1277     switch (typeSchema.which()) {
   1278       case schema::Type::VOID:
   1279         kind = FieldKind::PRIMITIVE;
   1280         setterDefault = " = ::capnp::VOID";
   1281         break;
   1282 
   1283 #define HANDLE_PRIMITIVE(discrim, typeName, defaultName, suffix) \
   1284       case schema::Type::discrim: \
   1285         kind = FieldKind::PRIMITIVE; \
   1286         if (defaultBody.get##defaultName() != 0) { \
   1287           defaultMask = kj::str(defaultBody.get##defaultName(), #suffix); \
   1288         } \
   1289         break;
   1290 
   1291       HANDLE_PRIMITIVE(BOOL, bool, Bool, );
   1292       HANDLE_PRIMITIVE(INT8 , ::int8_t , Int8 , );
   1293       HANDLE_PRIMITIVE(INT16, ::int16_t, Int16, );
   1294       HANDLE_PRIMITIVE(INT32, ::int32_t, Int32, );
   1295       HANDLE_PRIMITIVE(INT64, ::int64_t, Int64, ll);
   1296       HANDLE_PRIMITIVE(UINT8 , ::uint8_t , Uint8 , u);
   1297       HANDLE_PRIMITIVE(UINT16, ::uint16_t, Uint16, u);
   1298       HANDLE_PRIMITIVE(UINT32, ::uint32_t, Uint32, u);
   1299       HANDLE_PRIMITIVE(UINT64, ::uint64_t, Uint64, ull);
   1300 #undef HANDLE_PRIMITIVE
   1301 
   1302       case schema::Type::FLOAT32:
   1303         kind = FieldKind::PRIMITIVE;
   1304         if (defaultBody.getFloat32() != 0) {
   1305           uint32_t mask;
   1306           float value = defaultBody.getFloat32();
   1307           static_assert(sizeof(mask) == sizeof(value), "bug");
   1308           memcpy(&mask, &value, sizeof(mask));
   1309           defaultMask = kj::str(mask, "u");
   1310         }
   1311         break;
   1312 
   1313       case schema::Type::FLOAT64:
   1314         kind = FieldKind::PRIMITIVE;
   1315         if (defaultBody.getFloat64() != 0) {
   1316           uint64_t mask;
   1317           double value = defaultBody.getFloat64();
   1318           static_assert(sizeof(mask) == sizeof(value), "bug");
   1319           memcpy(&mask, &value, sizeof(mask));
   1320           defaultMask = kj::str(mask, "ull");
   1321         }
   1322         break;
   1323 
   1324       case schema::Type::TEXT:
   1325         kind = FieldKind::BLOB;
   1326         if (defaultBody.hasText()) {
   1327           defaultOffset = field.getDefaultValueSchemaOffset();
   1328           defaultSize = defaultBody.getText().size();
   1329         }
   1330         break;
   1331       case schema::Type::DATA:
   1332         kind = FieldKind::BLOB;
   1333         if (defaultBody.hasData()) {
   1334           defaultOffset = field.getDefaultValueSchemaOffset();
   1335           defaultSize = defaultBody.getData().size();
   1336         }
   1337         break;
   1338 
   1339       case schema::Type::ENUM:
   1340         kind = FieldKind::PRIMITIVE;
   1341         if (defaultBody.getEnum() != 0) {
   1342           defaultMask = kj::str(defaultBody.getEnum(), "u");
   1343         }
   1344         break;
   1345 
   1346       case schema::Type::STRUCT:
   1347         kind = FieldKind::STRUCT;
   1348         if (defaultBody.hasStruct()) {
   1349           defaultOffset = field.getDefaultValueSchemaOffset();
   1350         }
   1351         break;
   1352       case schema::Type::LIST:
   1353         kind = FieldKind::LIST;
   1354         if (defaultBody.hasList()) {
   1355           defaultOffset = field.getDefaultValueSchemaOffset();
   1356         }
   1357         break;
   1358       case schema::Type::INTERFACE:
   1359         kind = FieldKind::INTERFACE;
   1360         break;
   1361       case schema::Type::ANY_POINTER:
   1362         if (defaultBody.hasAnyPointer()) {
   1363           defaultOffset = field.getDefaultValueSchemaOffset();
   1364         }
   1365         if (typeSchema.getBrandParameter() != nullptr) {
   1366           kind = FieldKind::BRAND_PARAMETER;
   1367         } else {
   1368           kind = FieldKind::ANY_POINTER;
   1369           switch (typeSchema.whichAnyPointerKind()) {
   1370             case schema::Type::AnyPointer::Unconstrained::ANY_KIND:
   1371               kind = FieldKind::ANY_POINTER;
   1372               break;
   1373             case schema::Type::AnyPointer::Unconstrained::STRUCT:
   1374               kind = FieldKind::STRUCT;
   1375               break;
   1376             case schema::Type::AnyPointer::Unconstrained::LIST:
   1377               kind = FieldKind::LIST;
   1378               break;
   1379             case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
   1380               kind = FieldKind::INTERFACE;
   1381               break;
   1382           }
   1383         }
   1384         break;
   1385     }
   1386 
   1387     kj::String defaultMaskParam;
   1388     if (defaultMask.size() > 0) {
   1389       defaultMaskParam = kj::str(", ", defaultMask);
   1390     }
   1391 
   1392     uint offset = slot.getOffset();
   1393 
   1394     if (kind == FieldKind::PRIMITIVE) {
   1395       return FieldText {
   1396         kj::strTree(
   1397             kj::mv(unionDiscrim.readerIsDecl),
   1398             "  inline ", type, " get", titleCase, "() const;\n"
   1399             "\n"),
   1400 
   1401         kj::strTree(
   1402             kj::mv(unionDiscrim.builderIsDecl),
   1403             "  inline ", type, " get", titleCase, "();\n"
   1404             "  inline void set", titleCase, "(", type, " value", setterDefault, ");\n"
   1405             "\n"),
   1406 
   1407         kj::strTree(),
   1408 
   1409         kj::strTree(
   1410             kj::mv(unionDiscrim.isDefs),
   1411             templateContext.allDecls(),
   1412             "inline ", type, " ", scope, "Reader::get", titleCase, "() const {\n",
   1413             unionDiscrim.check,
   1414             "  return _reader.getDataField<", type, ">(\n"
   1415             "      ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS", defaultMaskParam, ");\n",
   1416             "}\n"
   1417             "\n",
   1418             templateContext.allDecls(),
   1419             "inline ", type, " ", scope, "Builder::get", titleCase, "() {\n",
   1420             unionDiscrim.check,
   1421             "  return _builder.getDataField<", type, ">(\n"
   1422             "      ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS", defaultMaskParam, ");\n",
   1423             "}\n",
   1424             templateContext.allDecls(),
   1425             "inline void ", scope, "Builder::set", titleCase, "(", type, " value) {\n",
   1426             unionDiscrim.set,
   1427             "  _builder.setDataField<", type, ">(\n"
   1428             "      ::capnp::bounded<", offset, ">() * ::capnp::ELEMENTS, value", defaultMaskParam, ");\n",
   1429             "}\n"
   1430             "\n")
   1431       };
   1432 
   1433     } else if (kind == FieldKind::INTERFACE) {
   1434       CppTypeName clientType = type;
   1435       clientType.addMemberType("Client");
   1436 
   1437       return FieldText {
   1438         kj::strTree(
   1439             kj::mv(unionDiscrim.readerIsDecl),
   1440             "  inline bool has", titleCase, "() const;\n"
   1441             "#if !CAPNP_LITE\n"
   1442             "  inline ", clientType, " get", titleCase, "() const;\n"
   1443             "#endif  // !CAPNP_LITE\n"
   1444             "\n"),
   1445 
   1446         kj::strTree(
   1447             kj::mv(unionDiscrim.builderIsDecl),
   1448             "  inline bool has", titleCase, "();\n"
   1449             "#if !CAPNP_LITE\n"
   1450             "  inline ", clientType, " get", titleCase, "();\n"
   1451             "  inline void set", titleCase, "(", clientType, "&& value);\n",
   1452             "  inline void set", titleCase, "(", clientType, "& value);\n",
   1453             "  inline void adopt", titleCase, "(::capnp::Orphan<", type, ">&& value);\n"
   1454             "  inline ::capnp::Orphan<", type, "> disown", titleCase, "();\n"
   1455             "#endif  // !CAPNP_LITE\n"
   1456             "\n"),
   1457 
   1458         kj::strTree(
   1459             hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree(
   1460               "  inline ", clientType, " get", titleCase, "();\n")),
   1461 
   1462         kj::strTree(
   1463             kj::mv(unionDiscrim.isDefs),
   1464             templateContext.allDecls(),
   1465             "inline bool ", scope, "Reader::has", titleCase, "() const {\n",
   1466             unionDiscrim.has,
   1467             "  return !_reader.getPointerField(\n"
   1468             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1469             "}\n",
   1470             templateContext.allDecls(),
   1471             "inline bool ", scope, "Builder::has", titleCase, "() {\n",
   1472             unionDiscrim.has,
   1473             "  return !_builder.getPointerField(\n"
   1474             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1475             "}\n"
   1476             "#if !CAPNP_LITE\n",
   1477             templateContext.allDecls(),
   1478             "inline ", clientType, " ", scope, "Reader::get", titleCase, "() const {\n",
   1479             unionDiscrim.check,
   1480             "  return ::capnp::_::PointerHelpers<", type, ">::get(_reader.getPointerField(\n"
   1481             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1482             "}\n",
   1483             templateContext.allDecls(),
   1484             "inline ", clientType, " ", scope, "Builder::get", titleCase, "() {\n",
   1485             unionDiscrim.check,
   1486             "  return ::capnp::_::PointerHelpers<", type, ">::get(_builder.getPointerField(\n"
   1487             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1488             "}\n",
   1489             hasDiscriminantValue(proto) ? kj::strTree() : kj::strTree(
   1490               templateContext.allDecls(),
   1491               "inline ", clientType, " ", scope, "Pipeline::get", titleCase, "() {\n",
   1492               "  return ", clientType, "(_typeless.getPointerField(", offset, ").asCap());\n"
   1493               "}\n"),
   1494             templateContext.allDecls(),
   1495             "inline void ", scope, "Builder::set", titleCase, "(", clientType, "&& cap) {\n",
   1496             unionDiscrim.set,
   1497             "  ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n"
   1498             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(cap));\n"
   1499             "}\n",
   1500             templateContext.allDecls(),
   1501             "inline void ", scope, "Builder::set", titleCase, "(", clientType, "& cap) {\n",
   1502             unionDiscrim.set,
   1503             "  ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n"
   1504             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), cap);\n"
   1505             "}\n",
   1506             templateContext.allDecls(),
   1507             "inline void ", scope, "Builder::adopt", titleCase, "(\n"
   1508             "    ::capnp::Orphan<", type, ">&& value) {\n",
   1509             unionDiscrim.set,
   1510             "  ::capnp::_::PointerHelpers<", type, ">::adopt(_builder.getPointerField(\n"
   1511             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(value));\n"
   1512             "}\n",
   1513             templateContext.allDecls(),
   1514             "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n",
   1515             unionDiscrim.check,
   1516             "  return ::capnp::_::PointerHelpers<", type, ">::disown(_builder.getPointerField(\n"
   1517             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1518             "}\n"
   1519             "#endif  // !CAPNP_LITE\n"
   1520             "\n")
   1521       };
   1522 
   1523     } else if (kind == FieldKind::ANY_POINTER) {
   1524       return FieldText {
   1525         kj::strTree(
   1526             kj::mv(unionDiscrim.readerIsDecl),
   1527             "  inline bool has", titleCase, "() const;\n"
   1528             "  inline ::capnp::AnyPointer::Reader get", titleCase, "() const;\n"
   1529             "\n"),
   1530 
   1531         kj::strTree(
   1532             kj::mv(unionDiscrim.builderIsDecl),
   1533             "  inline bool has", titleCase, "();\n"
   1534             "  inline ::capnp::AnyPointer::Builder get", titleCase, "();\n"
   1535             "  inline ::capnp::AnyPointer::Builder init", titleCase, "();\n"
   1536             "\n"),
   1537 
   1538         kj::strTree(),
   1539 
   1540         kj::strTree(
   1541             kj::mv(unionDiscrim.isDefs),
   1542             templateContext.allDecls(),
   1543             "inline bool ", scope, "Reader::has", titleCase, "() const {\n",
   1544             unionDiscrim.has,
   1545             "  return !_reader.getPointerField(\n"
   1546             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1547             "}\n",
   1548             templateContext.allDecls(),
   1549             "inline bool ", scope, "Builder::has", titleCase, "() {\n",
   1550             unionDiscrim.has,
   1551             "  return !_builder.getPointerField(\n"
   1552             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1553             "}\n",
   1554             templateContext.allDecls(),
   1555             "inline ::capnp::AnyPointer::Reader ", scope, "Reader::get", titleCase, "() const {\n",
   1556             unionDiscrim.check,
   1557             "  return ::capnp::AnyPointer::Reader(_reader.getPointerField(\n"
   1558             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1559             "}\n",
   1560             templateContext.allDecls(),
   1561             "inline ::capnp::AnyPointer::Builder ", scope, "Builder::get", titleCase, "() {\n",
   1562             unionDiscrim.check,
   1563             "  return ::capnp::AnyPointer::Builder(_builder.getPointerField(\n"
   1564             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1565             "}\n",
   1566             templateContext.allDecls(),
   1567             "inline ::capnp::AnyPointer::Builder ", scope, "Builder::init", titleCase, "() {\n",
   1568             unionDiscrim.set,
   1569             "  auto result = ::capnp::AnyPointer::Builder(_builder.getPointerField(\n"
   1570             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1571             "  result.clear();\n"
   1572             "  return result;\n"
   1573             "}\n"
   1574             "\n")
   1575       };
   1576 
   1577     } else {
   1578       // Blob, struct, list, or template param.  These have only minor differences.
   1579 
   1580       uint64_t typeId = field.getContainingStruct().getProto().getId();
   1581       kj::String defaultParam = defaultOffset == 0 ? kj::str() : kj::str(
   1582           ",\n        ::capnp::schemas::bp_", kj::hex(typeId), " + ", defaultOffset,
   1583           defaultSize == 0 ? kj::strTree() : kj::strTree(", ", defaultSize));
   1584 
   1585       bool shouldIncludeStructInit =
   1586           kind == FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER;
   1587       bool shouldIncludeSizedInit =
   1588           kind != FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER;
   1589       bool shouldIncludePipelineGetter = !hasDiscriminantValue(proto) &&
   1590           (kind == FieldKind::STRUCT || kind == FieldKind::BRAND_PARAMETER);
   1591       bool shouldIncludeArrayInitializer = false;
   1592       bool shouldExcludeInLiteMode = type.hasInterfaces();
   1593       bool shouldTemplatizeInit = typeSchema.which() == schema::Type::ANY_POINTER &&
   1594           kind != FieldKind::BRAND_PARAMETER;
   1595 
   1596       CppTypeName elementReaderType;
   1597       if (typeSchema.isList()) {
   1598         bool primitiveElement = false;
   1599         bool interface = false;
   1600         auto elementType = typeSchema.asList().getElementType();
   1601         switch (elementType.which()) {
   1602           case schema::Type::VOID:
   1603           case schema::Type::BOOL:
   1604           case schema::Type::INT8:
   1605           case schema::Type::INT16:
   1606           case schema::Type::INT32:
   1607           case schema::Type::INT64:
   1608           case schema::Type::UINT8:
   1609           case schema::Type::UINT16:
   1610           case schema::Type::UINT32:
   1611           case schema::Type::UINT64:
   1612           case schema::Type::FLOAT32:
   1613           case schema::Type::FLOAT64:
   1614           case schema::Type::ENUM:
   1615             primitiveElement = true;
   1616             shouldIncludeArrayInitializer = true;
   1617             break;
   1618 
   1619           case schema::Type::TEXT:
   1620           case schema::Type::DATA:
   1621           case schema::Type::LIST:
   1622             primitiveElement = false;
   1623             shouldIncludeArrayInitializer = true;
   1624             break;
   1625 
   1626           case schema::Type::ANY_POINTER:
   1627             primitiveElement = false;
   1628             shouldIncludeArrayInitializer = elementType.getBrandParameter() != nullptr;
   1629             break;
   1630 
   1631           case schema::Type::INTERFACE:
   1632             primitiveElement = false;
   1633             interface = true;
   1634             break;
   1635 
   1636           case schema::Type::STRUCT:
   1637             primitiveElement = false;
   1638             break;
   1639         }
   1640         elementReaderType = typeName(elementType, nullptr);
   1641         if (!primitiveElement) {
   1642           if (interface) {
   1643             elementReaderType.addMemberType("Client");
   1644           } else {
   1645             elementReaderType.addMemberType("Reader");
   1646           }
   1647         }
   1648       };
   1649 
   1650       CppTypeName readerType;
   1651       CppTypeName builderType;
   1652       CppTypeName pipelineType;
   1653       if (kind == FieldKind::BRAND_PARAMETER) {
   1654         readerType = CppTypeName::makeNamespace("capnp");
   1655         readerType.addMemberTemplate("ReaderFor", kj::heapArray(&type, 1));
   1656         builderType = CppTypeName::makeNamespace("capnp");
   1657         builderType.addMemberTemplate("BuilderFor", kj::heapArray(&type, 1));
   1658         pipelineType = CppTypeName::makeNamespace("capnp");
   1659         pipelineType.addMemberTemplate("PipelineFor", kj::heapArray(&type, 1));
   1660       } else {
   1661         readerType = type;
   1662         readerType.addMemberType("Reader");
   1663         builderType = type;
   1664         builderType.addMemberType("Builder");
   1665         pipelineType = type;
   1666         pipelineType.addMemberType("Pipeline");
   1667       }
   1668 
   1669       #define COND(cond, ...) ((cond) ? kj::strTree(__VA_ARGS__) : kj::strTree())
   1670 
   1671       return FieldText {
   1672         kj::strTree(
   1673             kj::mv(unionDiscrim.readerIsDecl),
   1674             "  inline bool has", titleCase, "() const;\n",
   1675             COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"),
   1676             "  inline ", readerType, " get", titleCase, "() const;\n",
   1677             COND(shouldExcludeInLiteMode, "#endif  // !CAPNP_LITE\n"),
   1678             "\n"),
   1679 
   1680         kj::strTree(
   1681             kj::mv(unionDiscrim.builderIsDecl),
   1682             "  inline bool has", titleCase, "();\n",
   1683             COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"),
   1684             "  inline ", builderType, " get", titleCase, "();\n"
   1685             "  inline void set", titleCase, "(", readerType, " value);\n",
   1686             COND(shouldIncludeArrayInitializer,
   1687               "  inline void set", titleCase, "(::kj::ArrayPtr<const ", elementReaderType, "> value);\n"),
   1688             COND(shouldIncludeStructInit,
   1689               COND(shouldTemplatizeInit,
   1690                 "  template <typename T_>\n"
   1691                 "  inline ::capnp::BuilderFor<T_> init", titleCase, "As();\n"),
   1692               COND(!shouldTemplatizeInit,
   1693                 "  inline ", builderType, " init", titleCase, "();\n")),
   1694             COND(shouldIncludeSizedInit,
   1695               COND(shouldTemplatizeInit,
   1696                 "  template <typename T_>\n"
   1697                 "  inline ::capnp::BuilderFor<T_> init", titleCase, "As(unsigned int size);\n"),
   1698               COND(!shouldTemplatizeInit,
   1699                 "  inline ", builderType, " init", titleCase, "(unsigned int size);\n")),
   1700             "  inline void adopt", titleCase, "(::capnp::Orphan<", type, ">&& value);\n"
   1701             "  inline ::capnp::Orphan<", type, "> disown", titleCase, "();\n",
   1702             COND(shouldExcludeInLiteMode, "#endif  // !CAPNP_LITE\n"),
   1703             "\n"),
   1704 
   1705         kj::strTree(
   1706             COND(shouldIncludePipelineGetter,
   1707               "  inline ", pipelineType, " get", titleCase, "();\n")),
   1708 
   1709         kj::strTree(
   1710             kj::mv(unionDiscrim.isDefs),
   1711             templateContext.allDecls(),
   1712             "inline bool ", scope, "Reader::has", titleCase, "() const {\n",
   1713             unionDiscrim.has,
   1714             "  return !_reader.getPointerField(\n"
   1715             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1716             "}\n",
   1717             templateContext.allDecls(),
   1718             "inline bool ", scope, "Builder::has", titleCase, "() {\n",
   1719             unionDiscrim.has,
   1720             "  return !_builder.getPointerField(\n"
   1721             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS).isNull();\n"
   1722             "}\n",
   1723             COND(shouldExcludeInLiteMode, "#if !CAPNP_LITE\n"),
   1724             templateContext.allDecls(),
   1725             "inline ", readerType, " ", scope, "Reader::get", titleCase, "() const {\n",
   1726             unionDiscrim.check,
   1727             "  return ::capnp::_::PointerHelpers<", type, ">::get(_reader.getPointerField(\n"
   1728             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS)", defaultParam, ");\n"
   1729             "}\n",
   1730             templateContext.allDecls(),
   1731             "inline ", builderType, " ", scope, "Builder::get", titleCase, "() {\n",
   1732             unionDiscrim.check,
   1733             "  return ::capnp::_::PointerHelpers<", type, ">::get(_builder.getPointerField(\n"
   1734             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS)", defaultParam, ");\n"
   1735             "}\n",
   1736             COND(shouldIncludePipelineGetter,
   1737               "#if !CAPNP_LITE\n",
   1738               templateContext.allDecls(),
   1739               "inline ", pipelineType, " ", scope, "Pipeline::get", titleCase, "() {\n",
   1740               "  return ", pipelineType, "(_typeless.getPointerField(", offset, "));\n"
   1741               "}\n"
   1742               "#endif  // !CAPNP_LITE\n"),
   1743             templateContext.allDecls(),
   1744             "inline void ", scope, "Builder::set", titleCase, "(", readerType, " value) {\n",
   1745             unionDiscrim.set,
   1746             "  ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n"
   1747             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), value);\n"
   1748             "}\n",
   1749             COND(shouldIncludeArrayInitializer,
   1750               templateContext.allDecls(),
   1751               "inline void ", scope, "Builder::set", titleCase, "(::kj::ArrayPtr<const ", elementReaderType, "> value) {\n",
   1752               unionDiscrim.set,
   1753               "  ::capnp::_::PointerHelpers<", type, ">::set(_builder.getPointerField(\n"
   1754             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), value);\n"
   1755               "}\n"),
   1756             COND(shouldIncludeStructInit,
   1757               COND(shouldTemplatizeInit,
   1758                 templateContext.allDecls(),
   1759                 "template <typename T_>\n"
   1760                 "inline ::capnp::BuilderFor<T_> ", scope, "Builder::init", titleCase, "As() {\n",
   1761                 "  static_assert(::capnp::kind<T_>() == ::capnp::Kind::STRUCT,\n"
   1762                 "                \"", proto.getName(), " must be a struct\");\n",
   1763                 unionDiscrim.set,
   1764                 "  return ::capnp::_::PointerHelpers<T_>::init(_builder.getPointerField(\n"
   1765                 "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1766                 "}\n"),
   1767               COND(!shouldTemplatizeInit,
   1768                 templateContext.allDecls(),
   1769                 "inline ", builderType, " ", scope, "Builder::init", titleCase, "() {\n",
   1770                 unionDiscrim.set,
   1771                 "  return ::capnp::_::PointerHelpers<", type, ">::init(_builder.getPointerField(\n"
   1772                 "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1773                 "}\n")),
   1774             COND(shouldIncludeSizedInit,
   1775               COND(shouldTemplatizeInit,
   1776                 templateContext.allDecls(),
   1777                 "template <typename T_>\n"
   1778                 "inline ::capnp::BuilderFor<T_> ", scope, "Builder::init", titleCase, "As(unsigned int size) {\n",
   1779                 "  static_assert(::capnp::kind<T_>() == ::capnp::Kind::LIST,\n"
   1780                 "                \"", proto.getName(), " must be a list\");\n",
   1781                 unionDiscrim.set,
   1782                 "  return ::capnp::_::PointerHelpers<T_>::init(_builder.getPointerField(\n"
   1783                 "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), size);\n"
   1784                 "}\n"),
   1785               COND(!shouldTemplatizeInit,
   1786                 templateContext.allDecls(),
   1787                 "inline ", builderType, " ", scope, "Builder::init", titleCase, "(unsigned int size) {\n",
   1788                 unionDiscrim.set,
   1789                 "  return ::capnp::_::PointerHelpers<", type, ">::init(_builder.getPointerField(\n"
   1790                 "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), size);\n"
   1791                 "}\n")),
   1792             templateContext.allDecls(),
   1793             "inline void ", scope, "Builder::adopt", titleCase, "(\n"
   1794             "    ::capnp::Orphan<", type, ">&& value) {\n",
   1795             unionDiscrim.set,
   1796             "  ::capnp::_::PointerHelpers<", type, ">::adopt(_builder.getPointerField(\n"
   1797             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS), kj::mv(value));\n"
   1798             "}\n",
   1799             COND(type.hasDisambiguatedTemplate(),
   1800                 "#if !defined(_MSC_VER) || defined(__clang__)\n"
   1801                 "// Excluded under MSVC because bugs may make it unable to compile this method.\n"),
   1802             templateContext.allDecls(),
   1803             "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n",
   1804             unionDiscrim.check,
   1805             "  return ::capnp::_::PointerHelpers<", type, ">::disown(_builder.getPointerField(\n"
   1806             "      ::capnp::bounded<", offset, ">() * ::capnp::POINTERS));\n"
   1807             "}\n",
   1808             COND(type.hasDisambiguatedTemplate(), "#endif  // !_MSC_VER || __clang__\n"),
   1809             COND(shouldExcludeInLiteMode, "#endif  // !CAPNP_LITE\n"),
   1810             "\n")
   1811       };
   1812 
   1813       #undef COND
   1814     }
   1815   }
   1816 
   1817   // -----------------------------------------------------------------
   1818 
   1819   enum class AsGenericRole { READER, BUILDER, CLIENT };
   1820 
   1821   kj::StringTree makeAsGenericDef(AsGenericRole role, const TemplateContext& templateContext,
   1822                                   kj::StringPtr type, kj::String innerType = kj::String()) {
   1823     if (!templateContext.isGeneric()) {
   1824       return kj::StringTree();
   1825     }
   1826     kj::StringTree self, up;
   1827     if (templateContext.hasParams()) {
   1828       auto returnType = [&]() {
   1829         return kj::strTree(type, templateContext.args("2"), innerType);
   1830       };
   1831       kj::StringTree asGeneric = kj::strTree("as", innerType.size() ? type : "", "Generic()");
   1832       switch (role) {
   1833         case AsGenericRole::READER:
   1834           self = kj::strTree(
   1835               "  ", templateContext.decl(true, "2"),
   1836               "  typename ", returnType(), "::Reader ", kj::mv(asGeneric), " {\n"
   1837               "    return typename ", returnType(), "::Reader(_reader);\n"
   1838               "  }\n"
   1839               "\n");
   1840           break;
   1841         case AsGenericRole::BUILDER:
   1842           self = kj::strTree(
   1843               "  ", templateContext.decl(true, "2"),
   1844               "  typename ", returnType(), "::Builder ", kj::mv(asGeneric), " {\n"
   1845               "    return typename ", returnType(), "::Builder(_builder);\n"
   1846               "  }\n"
   1847               "\n");
   1848           break;
   1849         case AsGenericRole::CLIENT:
   1850           self = kj::strTree(
   1851               "  ", templateContext.decl(true, "2"),
   1852               "  typename ", returnType(), "::Client ", kj::mv(asGeneric), " {\n"
   1853               "    return castAs<", innerType.size() ? "typename " : "", returnType(), ">();\n"
   1854               "  }\n"
   1855               "\n");
   1856           break;
   1857       }
   1858     }
   1859     KJ_IF_MAYBE(p, templateContext.getParent()) {
   1860       up = makeAsGenericDef(role, *p, p->getName(), kj::strTree(
   1861           templateContext.hasParams() ? "::template " : "::", type,
   1862           templateContext.args()).flatten());
   1863     }
   1864     return kj::strTree(kj::mv(self), kj::mv(up));
   1865   }
   1866 
   1867   // -----------------------------------------------------------------
   1868 
   1869   struct StructText {
   1870     kj::StringTree outerTypeDecl;
   1871     kj::StringTree outerTypeDef;
   1872     kj::StringTree readerBuilderDefs;
   1873     kj::StringTree inlineMethodDefs;
   1874     kj::StringTree sourceDefs;
   1875   };
   1876 
   1877   kj::StringTree makeReaderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
   1878                                const TemplateContext& templateContext, bool isUnion,
   1879                                kj::Array<kj::StringTree>&& methodDecls) {
   1880     return kj::strTree(
   1881         templateContext.allDecls(),
   1882         "class ", fullName, "::Reader {\n"
   1883         "public:\n"
   1884         "  typedef ", unqualifiedParentType, " Reads;\n"
   1885         "\n"
   1886         "  Reader() = default;\n"
   1887         "  inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}\n"
   1888         "\n"
   1889         "  inline ::capnp::MessageSize totalSize() const {\n"
   1890         "    return _reader.totalSize().asPublic();\n"
   1891         "  }\n"
   1892         "\n"
   1893         "#if !CAPNP_LITE\n"
   1894         "  inline ::kj::StringTree toString() const {\n"
   1895         "    return ::capnp::_::structString(_reader, *_capnpPrivate::brand());\n"
   1896         "  }\n"
   1897         "#endif  // !CAPNP_LITE\n"
   1898         "\n",
   1899         makeAsGenericDef(AsGenericRole::READER, templateContext, unqualifiedParentType),
   1900         isUnion ? kj::strTree("  inline Which which() const;\n") : kj::strTree(),
   1901         kj::mv(methodDecls),
   1902         "private:\n"
   1903         "  ::capnp::_::StructReader _reader;\n"
   1904         "  template <typename, ::capnp::Kind>\n"
   1905         "  friend struct ::capnp::ToDynamic_;\n"
   1906         "  template <typename, ::capnp::Kind>\n"
   1907         "  friend struct ::capnp::_::PointerHelpers;\n"
   1908         "  template <typename, ::capnp::Kind>\n"
   1909         "  friend struct ::capnp::List;\n"
   1910         "  friend class ::capnp::MessageBuilder;\n"
   1911         "  friend class ::capnp::Orphanage;\n"
   1912         "};\n"
   1913         "\n");
   1914   }
   1915 
   1916   kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
   1917                                 const TemplateContext& templateContext, bool isUnion,
   1918                                 kj::Array<kj::StringTree>&& methodDecls) {
   1919     return kj::strTree(
   1920         templateContext.allDecls(),
   1921         "class ", fullName, "::Builder {\n"
   1922         "public:\n"
   1923         "  typedef ", unqualifiedParentType, " Builds;\n"
   1924         "\n"
   1925         "  Builder() = delete;  // Deleted to discourage incorrect usage.\n"
   1926         "                       // You can explicitly initialize to nullptr instead.\n"
   1927         "  inline Builder(decltype(nullptr)) {}\n"
   1928         "  inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}\n"
   1929         "  inline operator Reader() const { return Reader(_builder.asReader()); }\n"
   1930         "  inline Reader asReader() const { return *this; }\n"
   1931         "\n"
   1932         "  inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }\n"
   1933         "#if !CAPNP_LITE\n"
   1934         "  inline ::kj::StringTree toString() const { return asReader().toString(); }\n"
   1935         "#endif  // !CAPNP_LITE\n"
   1936         "\n",
   1937         makeAsGenericDef(AsGenericRole::BUILDER, templateContext, unqualifiedParentType),
   1938         isUnion ? kj::strTree("  inline Which which();\n") : kj::strTree(),
   1939         kj::mv(methodDecls),
   1940         "private:\n"
   1941         "  ::capnp::_::StructBuilder _builder;\n"
   1942         "  template <typename, ::capnp::Kind>\n"
   1943         "  friend struct ::capnp::ToDynamic_;\n"
   1944         "  friend class ::capnp::Orphanage;\n",
   1945         "  template <typename, ::capnp::Kind>\n"
   1946         "  friend struct ::capnp::_::PointerHelpers;\n"
   1947         "};\n"
   1948         "\n");
   1949   }
   1950 
   1951   kj::StringTree makePipelineDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
   1952                                  const TemplateContext& templateContext, bool isUnion,
   1953                                  kj::Array<kj::StringTree>&& methodDecls) {
   1954     return kj::strTree(
   1955         "#if !CAPNP_LITE\n",
   1956         templateContext.allDecls(),
   1957         "class ", fullName, "::Pipeline {\n"
   1958         "public:\n"
   1959         "  typedef ", unqualifiedParentType, " Pipelines;\n"
   1960         "\n"
   1961         "  inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}\n"
   1962         "  inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)\n"
   1963         "      : _typeless(kj::mv(typeless)) {}\n"
   1964         "\n",
   1965         kj::mv(methodDecls),
   1966         "private:\n"
   1967         "  ::capnp::AnyPointer::Pipeline _typeless;\n"
   1968         "  friend class ::capnp::PipelineHook;\n"
   1969         "  template <typename, ::capnp::Kind>\n"
   1970         "  friend struct ::capnp::ToDynamic_;\n"
   1971         "};\n"
   1972         "#endif  // !CAPNP_LITE\n"
   1973         "\n");
   1974   }
   1975 
   1976   kj::StringTree makeGenericDeclarations(const TemplateContext& templateContext,
   1977                                          bool hasBrandDependencies) {
   1978     // Returns the declarations for the private members of a generic struct/interface;
   1979     // paired with the definitions from makeGenericDefinitions().
   1980     return kj::strTree(
   1981         "    static const ::capnp::_::RawBrandedSchema::Scope brandScopes[];\n"
   1982         "    static const ::capnp::_::RawBrandedSchema::Binding brandBindings[];\n",
   1983         (!hasBrandDependencies ? "" :
   1984             "    static const ::capnp::_::RawBrandedSchema::Dependency brandDependencies[];\n"),
   1985         "    static const ::capnp::_::RawBrandedSchema specificBrand;\n"
   1986         "    static constexpr ::capnp::_::RawBrandedSchema const* brand() { "
   1987         "return ::capnp::_::ChooseBrand<_capnpPrivate, ", templateContext.allArgs(), ">::brand(); }\n");
   1988   }
   1989 
   1990   kj::StringTree makeGenericDefinitions(
   1991       const TemplateContext& templateContext, kj::StringPtr fullName, kj::StringPtr hexId,
   1992       BrandInitializerText brandInitializers) {
   1993     // Returns the definitions for the members from makeGenericDeclarations().
   1994     bool hasBrandDependencies = (brandInitializers.dependencies.size() != 0);
   1995 
   1996     auto scopeCount = templateContext.getScopeMap().size();
   1997     auto dependencyCount = brandInitializers.dependencyCount;
   1998 
   1999     kj::String templates = kj::str(templateContext.allDecls());
   2000 
   2001     return kj::strTree(
   2002         templates, "const ::capnp::_::RawBrandedSchema::Scope ", fullName,
   2003         "::_capnpPrivate::brandScopes[] = ", kj::mv(brandInitializers.scopes), ";\n",
   2004 
   2005         templates, "const ::capnp::_::RawBrandedSchema::Binding ", fullName,
   2006         "::_capnpPrivate::brandBindings[] = ", kj::mv(brandInitializers.bindings), ";\n",
   2007 
   2008         (!hasBrandDependencies ? kj::strTree("") : kj::strTree(
   2009             templates, "const ::capnp::_::RawBrandedSchema::Dependency ", fullName,
   2010             "::_capnpPrivate::brandDependencies[] = ", kj::mv(brandInitializers.dependencies),
   2011             ";\n")),
   2012 
   2013         templates, "const ::capnp::_::RawBrandedSchema ", fullName, "::_capnpPrivate::specificBrand = {\n",
   2014         "  &::capnp::schemas::s_", hexId, ", brandScopes, ",
   2015         (!hasBrandDependencies ? "nullptr" : "brandDependencies"), ",\n",
   2016         "  ", scopeCount, ", ", dependencyCount,
   2017         ", nullptr\n"
   2018         "};\n");
   2019   }
   2020 
   2021   StructText makeStructText(kj::StringPtr scope, kj::StringPtr name, StructSchema schema,
   2022                             kj::Array<kj::StringTree> nestedTypeDecls,
   2023                             const TemplateContext& templateContext) {
   2024     auto proto = schema.getProto();
   2025     KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) {
   2026       name = annotatedName->getText();
   2027     }
   2028     auto fullName = kj::str(scope, name, templateContext.args());
   2029     auto subScope = kj::str(fullName, "::");
   2030     auto fieldTexts = KJ_MAP(f, schema.getFields()) {
   2031       return makeFieldText(subScope, f, templateContext);
   2032     };
   2033 
   2034     auto structNode = proto.getStruct();
   2035     uint discrimOffset = structNode.getDiscriminantOffset();
   2036     auto hexId = kj::hex(proto.getId());
   2037 
   2038     kj::String templates = kj::str(templateContext.allDecls());  // Ends with a newline
   2039 
   2040     // Private members struct
   2041     kj::StringTree declareText = kj::strTree(
   2042          "  struct _capnpPrivate {\n"
   2043          "    CAPNP_DECLARE_STRUCT_HEADER(", hexId, ", ", structNode.getDataWordCount(), ", ",
   2044          structNode.getPointerCount(), ")\n");
   2045 
   2046     kj::StringTree defineText = kj::strTree(
   2047         "// ", fullName, "\n",
   2048         templates, "constexpr uint16_t ", fullName, "::_capnpPrivate::dataWordSize;\n",
   2049         templates, "constexpr uint16_t ", fullName, "::_capnpPrivate::pointerCount;\n"
   2050         "#if !CAPNP_LITE\n",
   2051         templates, "constexpr ::capnp::Kind ", fullName, "::_capnpPrivate::kind;\n",
   2052         templates, "constexpr ::capnp::_::RawSchema const* ", fullName, "::_capnpPrivate::schema;\n");
   2053 
   2054     if (templateContext.isGeneric()) {
   2055       auto brandInitializers = makeBrandInitializers(templateContext, schema);
   2056       bool hasDeps = (brandInitializers.dependencies.size() != 0);
   2057 
   2058       declareText = kj::strTree(kj::mv(declareText),
   2059           "    #if !CAPNP_LITE\n",
   2060           makeGenericDeclarations(templateContext, hasDeps),
   2061           "    #endif  // !CAPNP_LITE\n");
   2062 
   2063       defineText = kj::strTree(kj::mv(defineText),
   2064           makeGenericDefinitions(
   2065               templateContext, fullName, kj::str(hexId), kj::mv(brandInitializers)));
   2066     } else {
   2067       declareText = kj::strTree(kj::mv(declareText),
   2068           "    #if !CAPNP_LITE\n"
   2069           "    static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }\n"
   2070           "    #endif  // !CAPNP_LITE\n");
   2071     }
   2072 
   2073     declareText = kj::strTree(kj::mv(declareText), "  };");
   2074     defineText = kj::strTree(kj::mv(defineText), "#endif  // !CAPNP_LITE\n\n");
   2075 
   2076     // Name of the ::Which type, when applicable.
   2077     CppTypeName whichName;
   2078     if (structNode.getDiscriminantCount() != 0) {
   2079       whichName = cppFullName(schema, nullptr);
   2080       whichName.addMemberType("Which");
   2081     }
   2082 
   2083     return StructText {
   2084       kj::strTree(
   2085           templateContext.hasParams() ? "  " : "", templateContext.decl(true),
   2086           "  struct ", name, ";\n"),
   2087 
   2088       kj::strTree(
   2089           templateContext.parentDecls(),
   2090           templateContext.decl(scope == nullptr),
   2091           "struct ", scope, name, " {\n",
   2092           "  ", name, "() = delete;\n"
   2093           "\n"
   2094           "  class Reader;\n"
   2095           "  class Builder;\n"
   2096           "  class Pipeline;\n",
   2097           structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree(
   2098               "  enum Which: uint16_t {\n",
   2099               KJ_MAP(f, structNode.getFields()) {
   2100                 if (hasDiscriminantValue(f)) {
   2101                   return kj::strTree("    ", toUpperCase(protoName(f)), ",\n");
   2102                 } else {
   2103                   return kj::strTree();
   2104                 }
   2105               },
   2106               "  };\n"),
   2107           KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); },
   2108           "\n",
   2109           kj::mv(declareText), "\n",
   2110           "};\n"
   2111           "\n"),
   2112 
   2113       kj::strTree(
   2114           makeReaderDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0,
   2115                         KJ_MAP(f, fieldTexts) { return kj::mv(f.readerMethodDecls); }),
   2116           makeBuilderDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0,
   2117                          KJ_MAP(f, fieldTexts) { return kj::mv(f.builderMethodDecls); }),
   2118           makePipelineDef(fullName, name, templateContext, structNode.getDiscriminantCount() != 0,
   2119                           KJ_MAP(f, fieldTexts) { return kj::mv(f.pipelineMethodDecls); })),
   2120 
   2121       kj::strTree(
   2122           structNode.getDiscriminantCount() == 0 ? kj::strTree() : kj::strTree(
   2123               templateContext.allDecls(),
   2124               "inline ", whichName, " ", fullName, "::Reader::which() const {\n"
   2125               "  return _reader.getDataField<Which>(\n"
   2126               "      ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS);\n"
   2127               "}\n",
   2128               templateContext.allDecls(),
   2129               "inline ", whichName, " ", fullName, "::Builder::which() {\n"
   2130               "  return _builder.getDataField<Which>(\n"
   2131               "      ::capnp::bounded<", discrimOffset, ">() * ::capnp::ELEMENTS);\n"
   2132               "}\n"
   2133               "\n"),
   2134           KJ_MAP(f, fieldTexts) { return kj::mv(f.inlineMethodDefs); }),
   2135 
   2136       kj::mv(defineText)
   2137     };
   2138   }
   2139 
   2140   // -----------------------------------------------------------------
   2141 
   2142   struct MethodText {
   2143     kj::StringTree clientDecls;
   2144     kj::StringTree serverDecls;
   2145     kj::StringTree inlineDefs;
   2146     kj::StringTree sourceDefs;
   2147     kj::StringTree dispatchCase;
   2148   };
   2149 
   2150   MethodText makeMethodText(kj::StringPtr interfaceName, InterfaceSchema::Method method,
   2151                             const TemplateContext& templateContext) {
   2152     auto proto = method.getProto();
   2153     auto name = protoName(proto);
   2154     auto titleCase = toTitleCase(name);
   2155     auto paramSchema = method.getParamType();
   2156     auto resultSchema = method.getResultType();
   2157     auto identifierName = safeIdentifier(name);
   2158 
   2159     auto paramProto = paramSchema.getProto();
   2160     auto resultProto = resultSchema.getProto();
   2161 
   2162     bool isStreaming = method.isStreaming();
   2163 
   2164     auto implicitParamsReader = proto.getImplicitParameters();
   2165     auto implicitParamsBuilder = kj::heapArrayBuilder<CppTypeName>(implicitParamsReader.size());
   2166     for (auto param: implicitParamsReader) {
   2167       implicitParamsBuilder.add(CppTypeName::makeTemplateParam(param.getName()));
   2168     }
   2169     auto implicitParams = implicitParamsBuilder.finish();
   2170 
   2171     kj::String implicitParamsTemplateDecl;
   2172     if (implicitParams.size() > 0) {
   2173       implicitParamsTemplateDecl = kj::str(
   2174           "template <", kj::StringTree(KJ_MAP(p, implicitParams) {
   2175             return kj::strTree("typename ", p);
   2176           }, ", "), ">\n");
   2177     }
   2178 
   2179 
   2180     CppTypeName interfaceTypeName = cppFullName(method.getContainingInterface(), nullptr);
   2181     CppTypeName paramType;
   2182     CppTypeName genericParamType;
   2183     if (paramProto.getScopeId() == 0) {
   2184       paramType = interfaceTypeName;
   2185       if (implicitParams.size() == 0) {
   2186         paramType.addMemberType(kj::str(titleCase, "Params"));
   2187         genericParamType = paramType;
   2188       } else {
   2189         genericParamType = paramType;
   2190         genericParamType.addMemberTemplate(kj::str(titleCase, "Params"), nullptr);
   2191         paramType.addMemberTemplate(kj::str(titleCase, "Params"),
   2192                                     kj::heapArray(implicitParams.asPtr()));
   2193       }
   2194     } else {
   2195       paramType = cppFullName(paramSchema, method);
   2196       genericParamType = cppFullName(paramSchema, nullptr);
   2197     }
   2198     CppTypeName resultType;
   2199     CppTypeName genericResultType;
   2200     if (isStreaming) {
   2201       // We don't use resultType or genericResultType in this case. We want to avoid computing them
   2202       // at all so that we don't end up marking stream.capnp.h in usedImports.
   2203     } else if (resultProto.getScopeId() == 0) {
   2204       resultType = interfaceTypeName;
   2205       if (implicitParams.size() == 0) {
   2206         resultType.addMemberType(kj::str(titleCase, "Results"));
   2207         genericResultType = resultType;
   2208       } else {
   2209         genericResultType = resultType;
   2210         genericResultType.addMemberTemplate(kj::str(titleCase, "Results"), nullptr);
   2211         resultType.addMemberTemplate(kj::str(titleCase, "Results"),
   2212                                      kj::heapArray(implicitParams.asPtr()));
   2213       }
   2214     } else {
   2215       resultType = cppFullName(resultSchema, method);
   2216       genericResultType = cppFullName(resultSchema, nullptr);
   2217     }
   2218 
   2219     kj::String shortParamType = paramProto.getScopeId() == 0 ?
   2220         kj::str(titleCase, "Params") : kj::str(genericParamType);
   2221     kj::String shortResultType = resultProto.getScopeId() == 0 || isStreaming ?
   2222         kj::str(titleCase, "Results") : kj::str(genericResultType);
   2223 
   2224     auto interfaceProto = method.getContainingInterface().getProto();
   2225     uint64_t interfaceId = interfaceProto.getId();
   2226     auto interfaceIdHex = kj::hex(interfaceId);
   2227     uint16_t methodId = method.getIndex();
   2228 
   2229     // TODO(msvc):  Notice that the return type of this method's request function is supposed to be
   2230     // `::capnp::Request<param, result>`. If the first template parameter to ::capnp::Request is a
   2231     // template instantiation, MSVC will sometimes complain that it's unspecialized and can't be
   2232     // used as a parameter in the return type (error C3203). It is not clear to me under what exact
   2233     // conditions this bug occurs, but it commonly crops up in test.capnp.h.
   2234     //
   2235     // The easiest (and only) workaround I found is to use C++14's return type deduction here, thus
   2236     // the `CAPNP_AUTO_IF_MSVC()` hackery in the return type declarations below. We're depending on
   2237     // the fact that that this function has an inline implementation for the deduction to work.
   2238 
   2239     auto requestMethodImpl = kj::strTree(
   2240         templateContext.allDecls(),
   2241         implicitParamsTemplateDecl,
   2242         templateContext.isGeneric() ? "CAPNP_AUTO_IF_MSVC(" : "",
   2243         isStreaming ? kj::strTree("::capnp::StreamingRequest<", paramType, ">")
   2244                     : kj::strTree("::capnp::Request<", paramType, ", ", resultType, ">"),
   2245         templateContext.isGeneric() ? ")\n" : "\n",
   2246         interfaceName, "::Client::", name, "Request(::kj::Maybe< ::capnp::MessageSize> sizeHint) {\n",
   2247         isStreaming
   2248             ? kj::strTree("  return newStreamingCall<", paramType, ">(\n")
   2249             : kj::strTree("  return newCall<", paramType, ", ", resultType, ">(\n"),
   2250         "      0x", interfaceIdHex, "ull, ", methodId, ", sizeHint);\n"
   2251         "}\n");
   2252 
   2253     return MethodText {
   2254       kj::strTree(
   2255           implicitParamsTemplateDecl.size() == 0 ? "" : "  ", implicitParamsTemplateDecl,
   2256           templateContext.isGeneric() ? "  CAPNP_AUTO_IF_MSVC(" : "  ",
   2257           isStreaming ? kj::strTree("::capnp::StreamingRequest<", paramType, ">")
   2258                       : kj::strTree("::capnp::Request<", paramType, ", ", resultType, ">"),
   2259           templateContext.isGeneric() ? ")" : "",
   2260           " ", name, "Request(\n"
   2261           "      ::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr);\n"),
   2262 
   2263       kj::strTree(
   2264           paramProto.getScopeId() != 0 ? kj::strTree() : kj::strTree(
   2265               "  typedef ", genericParamType, " ", titleCase, "Params;\n"),
   2266           resultProto.getScopeId() != 0 ? kj::strTree() : kj::strTree(
   2267               "  typedef ", genericResultType, " ", titleCase, "Results;\n"),
   2268           isStreaming
   2269               ? kj::strTree("  typedef ::capnp::StreamingCallContext<", shortParamType, "> ")
   2270               : kj::strTree(
   2271                   "  typedef ::capnp::CallContext<", shortParamType, ", ", shortResultType, "> "),
   2272               titleCase, "Context;\n"
   2273           "  virtual ::kj::Promise<void> ", identifierName, "(", titleCase, "Context context);\n"),
   2274 
   2275       implicitParams.size() == 0 ? kj::strTree() : kj::mv(requestMethodImpl),
   2276 
   2277       kj::strTree(
   2278           implicitParams.size() == 0 ? kj::mv(requestMethodImpl) : kj::strTree(),
   2279           templateContext.allDecls(),
   2280           "::kj::Promise<void> ", interfaceName, "::Server::", identifierName, "(", titleCase, "Context) {\n"
   2281           "  return ::capnp::Capability::Server::internalUnimplemented(\n"
   2282           "      \"", interfaceProto.getDisplayName(), "\", \"", name, "\",\n"
   2283           "      0x", interfaceIdHex, "ull, ", methodId, ");\n"
   2284           "}\n"),
   2285 
   2286       kj::strTree(
   2287           "    case ", methodId, ":\n",
   2288           isStreaming
   2289             ? kj::strTree(
   2290               // For streaming calls, we need to add an evalNow() here so that exceptions thrown
   2291               // directly from the call can propagate to later calls. If we don't capture the
   2292               // exception properly then the caller will never find out that this is a streaming
   2293               // call (indicated by the boolean in the return value) so won't know to propagate
   2294               // the exception.
   2295               "      return {\n"
   2296               "        kj::evalNow([&]() {\n"
   2297               "          return ", identifierName, "(::capnp::Capability::Server::internalGetTypedStreamingContext<\n"
   2298               "              ", genericParamType, ">(context));\n"
   2299               "        }),\n"
   2300               "        true\n"
   2301               "      };\n")
   2302             : kj::strTree(
   2303               // For non-streaming calls we let exceptions just flow through for a little more
   2304               // efficiency.
   2305               "      return {\n"
   2306               "        ", identifierName, "(::capnp::Capability::Server::internalGetTypedContext<\n"
   2307               "            ", genericParamType, ", ", genericResultType, ">(context)),\n"
   2308               "        false\n"
   2309               "      };\n"))
   2310     };
   2311   }
   2312 
   2313   struct InterfaceText {
   2314     kj::StringTree outerTypeDecl;
   2315     kj::StringTree outerTypeDef;
   2316     kj::StringTree clientServerDefs;
   2317     kj::StringTree inlineMethodDefs;
   2318     kj::StringTree sourceDefs;
   2319   };
   2320 
   2321   struct ExtendInfo {
   2322     CppTypeName typeName;
   2323     uint64_t id;
   2324   };
   2325 
   2326   void getTransitiveSuperclasses(InterfaceSchema schema, std::map<uint64_t, InterfaceSchema>& map) {
   2327     if (map.insert(std::make_pair(schema.getProto().getId(), schema)).second) {
   2328       for (auto sup: schema.getSuperclasses()) {
   2329         getTransitiveSuperclasses(sup, map);
   2330       }
   2331     }
   2332   }
   2333 
   2334   InterfaceText makeInterfaceText(kj::StringPtr scope, kj::StringPtr name, InterfaceSchema schema,
   2335                                   kj::Array<kj::StringTree> nestedTypeDecls,
   2336                                   const TemplateContext& templateContext) {
   2337     auto fullName = kj::str(scope, name, templateContext.args());
   2338     auto methods = KJ_MAP(m, schema.getMethods()) {
   2339       return makeMethodText(fullName, m, templateContext);
   2340     };
   2341 
   2342     auto proto = schema.getProto();
   2343     auto hexId = kj::hex(proto.getId());
   2344 
   2345     auto superclasses = KJ_MAP(superclass, schema.getSuperclasses()) {
   2346       return ExtendInfo { cppFullName(superclass, nullptr), superclass.getProto().getId() };
   2347     };
   2348 
   2349     kj::Array<ExtendInfo> transitiveSuperclasses;
   2350     {
   2351       std::map<uint64_t, InterfaceSchema> map;
   2352       getTransitiveSuperclasses(schema, map);
   2353       map.erase(schema.getProto().getId());
   2354       transitiveSuperclasses = KJ_MAP(entry, map) {
   2355         return ExtendInfo { cppFullName(entry.second, nullptr), entry.second.getProto().getId() };
   2356       };
   2357     }
   2358 
   2359     CppTypeName typeName = cppFullName(schema, nullptr);
   2360 
   2361     CppTypeName clientName = typeName;
   2362     clientName.addMemberType("Client");
   2363 
   2364     kj::String templates = kj::str(templateContext.allDecls());  // Ends with a newline
   2365 
   2366     // Private members struct
   2367     kj::StringTree declareText = kj::strTree(
   2368          "  #if !CAPNP_LITE\n"
   2369          "  struct _capnpPrivate {\n"
   2370          "    CAPNP_DECLARE_INTERFACE_HEADER(", hexId, ")\n");
   2371 
   2372     kj::StringTree defineText = kj::strTree(
   2373         "// ", fullName, "\n",
   2374         "#if !CAPNP_LITE\n",
   2375         templates, "constexpr ::capnp::Kind ", fullName, "::_capnpPrivate::kind;\n",
   2376         templates, "constexpr ::capnp::_::RawSchema const* ", fullName, "::_capnpPrivate::schema;\n");
   2377 
   2378     if (templateContext.isGeneric()) {
   2379       auto brandInitializers = makeBrandInitializers(templateContext, schema);
   2380       bool hasDeps = (brandInitializers.dependencies.size() != 0);
   2381 
   2382       declareText = kj::strTree(kj::mv(declareText),
   2383           makeGenericDeclarations(templateContext, hasDeps));
   2384 
   2385       defineText = kj::strTree(kj::mv(defineText),
   2386           makeGenericDefinitions(
   2387               templateContext, fullName, kj::str(hexId), kj::mv(brandInitializers)));
   2388     } else {
   2389       declareText = kj::strTree(kj::mv(declareText),
   2390         "    static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }\n");
   2391     }
   2392 
   2393     declareText = kj::strTree(kj::mv(declareText), "  };\n  #endif  // !CAPNP_LITE");
   2394     defineText = kj::strTree(kj::mv(defineText), "#endif  // !CAPNP_LITE\n\n");
   2395 
   2396     return InterfaceText {
   2397       kj::strTree(
   2398           templateContext.hasParams() ? "  " : "", templateContext.decl(true),
   2399           "  struct ", name, ";\n"),
   2400 
   2401       kj::strTree(
   2402           templateContext.parentDecls(),
   2403           templateContext.decl(scope == nullptr),
   2404           "struct ", scope, name, " {\n",
   2405           "  ", name, "() = delete;\n"
   2406           "\n"
   2407           "#if !CAPNP_LITE\n"
   2408           "  class Client;\n"
   2409           "  class Server;\n"
   2410           "#endif  // !CAPNP_LITE\n"
   2411           "\n",
   2412           KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); },
   2413           "\n",
   2414           kj::mv(declareText), "\n"
   2415           "};\n"
   2416           "\n"),
   2417 
   2418       kj::strTree(
   2419           "#if !CAPNP_LITE\n",
   2420           templateContext.allDecls(),
   2421           "class ", fullName, "::Client\n"
   2422           "    : public virtual ::capnp::Capability::Client",
   2423           KJ_MAP(s, superclasses) {
   2424             return kj::strTree(",\n      public virtual ", s.typeName.strNoTypename(), "::Client");
   2425           }, " {\n"
   2426           "public:\n"
   2427           "  typedef ", name, " Calls;\n"
   2428           "  typedef ", name, " Reads;\n"
   2429           "\n"
   2430           "  Client(decltype(nullptr));\n"
   2431           "  explicit Client(::kj::Own< ::capnp::ClientHook>&& hook);\n"
   2432           "  template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Server*>()>>\n"
   2433           "  Client(::kj::Own<_t>&& server);\n"
   2434           "  template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Client*>()>>\n"
   2435           "  Client(::kj::Promise<_t>&& promise);\n"
   2436           "  Client(::kj::Exception&& exception);\n"
   2437           "  Client(Client&) = default;\n"
   2438           "  Client(Client&&) = default;\n"
   2439           "  Client& operator=(Client& other);\n"
   2440           "  Client& operator=(Client&& other);\n"
   2441           "\n",
   2442           makeAsGenericDef(AsGenericRole::CLIENT, templateContext, name),
   2443           KJ_MAP(m, methods) { return kj::mv(m.clientDecls); },
   2444           "\n"
   2445           "protected:\n"
   2446           "  Client() = default;\n"
   2447           "};\n"
   2448           "\n",
   2449           templateContext.allDecls(),
   2450           "class ", fullName, "::Server\n"
   2451           "    : public virtual ::capnp::Capability::Server",
   2452           KJ_MAP(s, superclasses) {
   2453             return kj::strTree(",\n      public virtual ", s.typeName.strNoTypename(), "::Server");
   2454           }, " {\n"
   2455           "public:\n",
   2456           "  typedef ", name, " Serves;\n"
   2457           "\n"
   2458           "  ::capnp::Capability::Server::DispatchCallResult dispatchCall(\n"
   2459           "      uint64_t interfaceId, uint16_t methodId,\n"
   2460           "      ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context)\n"
   2461           "      override;\n"
   2462           "\n"
   2463           "protected:\n",
   2464           KJ_MAP(m, methods) { return kj::mv(m.serverDecls); },
   2465           "\n"
   2466           "  inline ", clientName, " thisCap() {\n"
   2467           "    return ::capnp::Capability::Server::thisCap()\n"
   2468           "        .template castAs<", typeName, ">();\n"
   2469           "  }\n"
   2470           "\n"
   2471           "  ::capnp::Capability::Server::DispatchCallResult dispatchCallInternal(\n"
   2472           "      uint16_t methodId,\n"
   2473           "      ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);\n"
   2474           "};\n"
   2475           "#endif  // !CAPNP_LITE\n"
   2476           "\n"),
   2477 
   2478       kj::strTree(
   2479           "#if !CAPNP_LITE\n",
   2480           templateContext.allDecls(),
   2481           "inline ", fullName, "::Client::Client(decltype(nullptr))\n"
   2482           "    : ::capnp::Capability::Client(nullptr) {}\n",
   2483           templateContext.allDecls(),
   2484           "inline ", fullName, "::Client::Client(\n"
   2485           "    ::kj::Own< ::capnp::ClientHook>&& hook)\n"
   2486           "    : ::capnp::Capability::Client(::kj::mv(hook)) {}\n",
   2487           templateContext.allDecls(),
   2488           "template <typename _t, typename>\n"
   2489           "inline ", fullName, "::Client::Client(::kj::Own<_t>&& server)\n"
   2490           "    : ::capnp::Capability::Client(::kj::mv(server)) {}\n",
   2491           templateContext.allDecls(),
   2492           "template <typename _t, typename>\n"
   2493           "inline ", fullName, "::Client::Client(::kj::Promise<_t>&& promise)\n"
   2494           "    : ::capnp::Capability::Client(::kj::mv(promise)) {}\n",
   2495           templateContext.allDecls(),
   2496           "inline ", fullName, "::Client::Client(::kj::Exception&& exception)\n"
   2497           "    : ::capnp::Capability::Client(::kj::mv(exception)) {}\n",
   2498           templateContext.allDecls(),
   2499           "inline ", clientName, "& ", fullName, "::Client::operator=(Client& other) {\n"
   2500           "  ::capnp::Capability::Client::operator=(other);\n"
   2501           "  return *this;\n"
   2502           "}\n",
   2503           templateContext.allDecls(),
   2504           "inline ", clientName, "& ", fullName, "::Client::operator=(Client&& other) {\n"
   2505           "  ::capnp::Capability::Client::operator=(kj::mv(other));\n"
   2506           "  return *this;\n"
   2507           "}\n"
   2508           "\n",
   2509           KJ_MAP(m, methods) { return kj::mv(m.inlineDefs); },
   2510           "#endif  // !CAPNP_LITE\n"),
   2511 
   2512       kj::strTree(
   2513           "#if !CAPNP_LITE\n",
   2514           KJ_MAP(m, methods) { return kj::mv(m.sourceDefs); },
   2515           templateContext.allDecls(),
   2516           "::capnp::Capability::Server::DispatchCallResult ", fullName, "::Server::dispatchCall(\n"
   2517           "    uint64_t interfaceId, uint16_t methodId,\n"
   2518           "    ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {\n"
   2519           "  switch (interfaceId) {\n"
   2520           "    case 0x", kj::hex(proto.getId()), "ull:\n"
   2521           "      return dispatchCallInternal(methodId, context);\n",
   2522           KJ_MAP(s, transitiveSuperclasses) {
   2523             return kj::strTree(
   2524               "    case 0x", kj::hex(s.id), "ull:\n"
   2525               "      return ", s.typeName.strNoTypename(),
   2526                          "::Server::dispatchCallInternal(methodId, context);\n");
   2527           },
   2528           "    default:\n"
   2529           "      return internalUnimplemented(\"", proto.getDisplayName(), "\", interfaceId);\n"
   2530           "  }\n"
   2531           "}\n",
   2532           templateContext.allDecls(),
   2533           "::capnp::Capability::Server::DispatchCallResult ", fullName, "::Server::dispatchCallInternal(\n"
   2534           "    uint16_t methodId,\n"
   2535           "    ::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {\n"
   2536           "  switch (methodId) {\n",
   2537           KJ_MAP(m, methods) { return kj::mv(m.dispatchCase); },
   2538           "    default:\n"
   2539           "      (void)context;\n"
   2540           "      return ::capnp::Capability::Server::internalUnimplemented(\n"
   2541           "          \"", proto.getDisplayName(), "\",\n"
   2542           "          0x", kj::hex(proto.getId()), "ull, methodId);\n"
   2543           "  }\n"
   2544           "}\n"
   2545           "#endif  // !CAPNP_LITE\n"
   2546           "\n",
   2547           kj::mv(defineText))
   2548     };
   2549   }
   2550 
   2551   // -----------------------------------------------------------------
   2552 
   2553   struct ConstText {
   2554     bool needsSchema;
   2555     kj::StringTree decl;
   2556     kj::StringTree def;
   2557   };
   2558 
   2559   ConstText makeConstText(kj::StringPtr scope, kj::StringPtr name, ConstSchema schema,
   2560                           const TemplateContext& templateContext) {
   2561     auto proto = schema.getProto();
   2562     auto constProto = proto.getConst();
   2563     auto type = schema.getType();
   2564     auto typeName_ = typeName(type, nullptr);
   2565     auto upperCase = toUpperCase(name);
   2566 
   2567     // Linkage qualifier for non-primitive types.
   2568     const char* linkage = scope.size() == 0 ? "extern " : "static ";
   2569 
   2570     switch (type.which()) {
   2571       case schema::Type::BOOL:
   2572       case schema::Type::INT8:
   2573       case schema::Type::INT16:
   2574       case schema::Type::INT32:
   2575       case schema::Type::INT64:
   2576       case schema::Type::UINT8:
   2577       case schema::Type::UINT16:
   2578       case schema::Type::UINT32:
   2579       case schema::Type::UINT64:
   2580       case schema::Type::ENUM:
   2581         return ConstText {
   2582           false,
   2583           kj::strTree("static constexpr ", typeName_, ' ', upperCase, " = ",
   2584               literalValue(schema.getType(), constProto.getValue()), ";\n"),
   2585           scope.size() == 0 ? kj::strTree() : kj::strTree(
   2586               // TODO(msvc): MSVC doesn't like definitions of constexprs, but other compilers and
   2587               //   the standard require them.
   2588               "#if !defined(_MSC_VER) || defined(__clang__)\n"
   2589               "constexpr ", typeName_, ' ', scope, upperCase, ";\n"
   2590               "#endif\n")
   2591         };
   2592 
   2593       case schema::Type::VOID:
   2594       case schema::Type::FLOAT32:
   2595       case schema::Type::FLOAT64: {
   2596         // TODO(msvc): MSVC doesn't like float- or class-typed constexprs. As soon as this is fixed,
   2597         //   treat VOID, FLOAT32, and FLOAT64 the same as the other primitives.
   2598         kj::String value = literalValue(schema.getType(), constProto.getValue()).flatten();
   2599         return ConstText {
   2600           false,
   2601           kj::strTree("static KJ_CONSTEXPR(const) ", typeName_, ' ', upperCase,
   2602               " CAPNP_NON_INT_CONSTEXPR_DECL_INIT(", value, ");\n"),
   2603           scope.size() == 0 ? kj::strTree() : kj::strTree(
   2604               "KJ_CONSTEXPR(const) ", typeName_, ' ', scope, upperCase,
   2605               " CAPNP_NON_INT_CONSTEXPR_DEF_INIT(", value, ");\n")
   2606         };
   2607       }
   2608 
   2609       case schema::Type::TEXT: {
   2610         kj::String constType = kj::strTree(
   2611             "::capnp::_::ConstText<", schema.as<Text>().size(), ">").flatten();
   2612         return ConstText {
   2613           true,
   2614           kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"),
   2615           kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_",
   2616                       kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n")
   2617         };
   2618       }
   2619 
   2620       case schema::Type::DATA: {
   2621         kj::String constType = kj::strTree(
   2622             "::capnp::_::ConstData<", schema.as<Data>().size(), ">").flatten();
   2623         return ConstText {
   2624           true,
   2625           kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"),
   2626           kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_",
   2627                       kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n")
   2628         };
   2629       }
   2630 
   2631       case schema::Type::STRUCT: {
   2632         kj::String constType = kj::strTree(
   2633             "::capnp::_::ConstStruct<", typeName_, ">").flatten();
   2634         return ConstText {
   2635           true,
   2636           kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"),
   2637           kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_",
   2638                       kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n")
   2639         };
   2640       }
   2641 
   2642       case schema::Type::LIST: {
   2643         kj::String constType = kj::strTree(
   2644             "::capnp::_::ConstList<", typeName(type.asList().getElementType(), nullptr), ">")
   2645             .flatten();
   2646         return ConstText {
   2647           true,
   2648           kj::strTree(linkage, "const ", constType, ' ', upperCase, ";\n"),
   2649           kj::strTree("const ", constType, ' ', scope, upperCase, "(::capnp::schemas::b_",
   2650                       kj::hex(proto.getId()), ".words + ", schema.getValueSchemaOffset(), ");\n")
   2651         };
   2652       }
   2653 
   2654       case schema::Type::ANY_POINTER:
   2655       case schema::Type::INTERFACE:
   2656         return ConstText { false, kj::strTree(), kj::strTree() };
   2657     }
   2658 
   2659     KJ_UNREACHABLE;
   2660   }
   2661 
   2662   // -----------------------------------------------------------------
   2663 
   2664   struct NodeText {
   2665     kj::StringTree outerTypeDecl;
   2666     kj::StringTree outerTypeDef;
   2667     kj::StringTree readerBuilderDefs;
   2668     kj::StringTree inlineMethodDefs;
   2669     kj::StringTree capnpSchemaDecls;
   2670     kj::StringTree capnpSchemaDefs;
   2671     kj::StringTree sourceFileDefs;
   2672   };
   2673 
   2674   NodeText makeNodeText(kj::StringPtr namespace_, kj::StringPtr scope,
   2675                         kj::StringPtr name, Schema schema,
   2676                         const TemplateContext& parentTemplateContext) {
   2677     // `templateContext` is something like "template <typename T>\ntemplate <typename U>\n"
   2678     // declaring template parameters for all parent scopes.
   2679 
   2680     auto proto = schema.getProto();
   2681     KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) {
   2682       name = annotatedName->getText();
   2683     }
   2684     auto hexId = kj::hex(proto.getId());
   2685 
   2686     TemplateContext templateContext(parentTemplateContext, name, proto);
   2687 
   2688     auto subScope = kj::str(scope, name, templateContext.args(), "::");
   2689 
   2690     // Compute nested nodes, including groups.
   2691     kj::Vector<NodeText> nestedTexts(proto.getNestedNodes().size());
   2692     for (auto nested: proto.getNestedNodes()) {
   2693       nestedTexts.add(makeNodeText(
   2694           namespace_, subScope, nested.getName(), schemaLoader.getUnbound(nested.getId()),\
   2695           templateContext));
   2696     };
   2697 
   2698     if (proto.isStruct()) {
   2699       for (auto field: proto.getStruct().getFields()) {
   2700         if (field.isGroup()) {
   2701           nestedTexts.add(makeNodeText(
   2702               namespace_, subScope, toTitleCase(protoName(field)),
   2703               schemaLoader.getUnbound(field.getGroup().getTypeId()),
   2704               templateContext));
   2705         }
   2706       }
   2707     } else if (proto.isInterface()) {
   2708       for (auto method: proto.getInterface().getMethods()) {
   2709         {
   2710           Schema params = schemaLoader.getUnbound(method.getParamStructType());
   2711           auto paramsProto = schemaLoader.getUnbound(method.getParamStructType()).getProto();
   2712           if (paramsProto.getScopeId() == 0) {
   2713             nestedTexts.add(makeNodeText(namespace_, subScope,
   2714                 toTitleCase(kj::str(protoName(method), "Params")), params, templateContext));
   2715           }
   2716         }
   2717         {
   2718           Schema results = schemaLoader.getUnbound(method.getResultStructType());
   2719           auto resultsProto = schemaLoader.getUnbound(method.getResultStructType()).getProto();
   2720           if (resultsProto.getScopeId() == 0) {
   2721             nestedTexts.add(makeNodeText(namespace_, subScope,
   2722                 toTitleCase(kj::str(protoName(method), "Results")), results, templateContext));
   2723           }
   2724         }
   2725       }
   2726     }
   2727 
   2728     // Convert the encoded schema to a literal byte array.
   2729     kj::ArrayPtr<const word> rawSchema = schema.asUncheckedMessage();
   2730     auto schemaLiteral = kj::StringTree(KJ_MAP(w, rawSchema) {
   2731       const byte* bytes = reinterpret_cast<const byte*>(&w);
   2732 
   2733       return kj::strTree(KJ_MAP(i, kj::range<uint>(0, sizeof(word))) {
   2734         auto text = kj::toCharSequence(kj::implicitCast<uint>(bytes[i]));
   2735         return kj::strTree(kj::repeat(' ', 4 - text.size()), text, ",");
   2736       });
   2737     }, "\n   ");
   2738 
   2739     auto schemaDecl = kj::strTree(
   2740         "CAPNP_DECLARE_SCHEMA(", hexId, ");\n");
   2741 
   2742     std::set<uint64_t> deps;
   2743     enumerateDeps(proto, deps);
   2744 
   2745     kj::Array<uint> membersByName;
   2746     kj::Array<uint> membersByDiscrim;
   2747     switch (proto.which()) {
   2748       case schema::Node::STRUCT: {
   2749         auto structSchema = schema.asStruct();
   2750         membersByName = makeMembersByName(structSchema.getFields());
   2751         auto builder = kj::heapArrayBuilder<uint>(structSchema.getFields().size());
   2752         for (auto field: structSchema.getUnionFields()) {
   2753           builder.add(field.getIndex());
   2754         }
   2755         for (auto field: structSchema.getNonUnionFields()) {
   2756           builder.add(field.getIndex());
   2757         }
   2758         membersByDiscrim = builder.finish();
   2759         break;
   2760       }
   2761       case schema::Node::ENUM:
   2762         membersByName = makeMembersByName(schema.asEnum().getEnumerants());
   2763         break;
   2764       case schema::Node::INTERFACE:
   2765         membersByName = makeMembersByName(schema.asInterface().getMethods());
   2766         break;
   2767       default:
   2768         break;
   2769     }
   2770 
   2771     auto brandDeps = makeBrandDepInitializers(
   2772         makeBrandDepMap(templateContext, schema.getGeneric()));
   2773 
   2774     auto schemaDef = kj::strTree(
   2775         "static const ::capnp::_::AlignedData<", rawSchema.size(), "> b_", hexId, " = {\n"
   2776         "  {", kj::mv(schemaLiteral), " }\n"
   2777         "};\n"
   2778         "::capnp::word const* const bp_", hexId, " = b_", hexId, ".words;\n"
   2779         "#if !CAPNP_LITE\n",
   2780         deps.size() == 0 ? kj::strTree() : kj::strTree(
   2781             "static const ::capnp::_::RawSchema* const d_", hexId, "[] = {\n",
   2782             KJ_MAP(depId, deps) {
   2783               return kj::strTree("  &s_", kj::hex(depId), ",\n");
   2784             },
   2785             "};\n"),
   2786         membersByName.size() == 0 ? kj::strTree() : kj::strTree(
   2787             "static const uint16_t m_", hexId, "[] = {",
   2788             kj::StringTree(KJ_MAP(index, membersByName) { return kj::strTree(index); }, ", "),
   2789             "};\n"),
   2790         membersByDiscrim.size() == 0 ? kj::strTree() : kj::strTree(
   2791             "static const uint16_t i_", hexId, "[] = {",
   2792             kj::StringTree(KJ_MAP(index, membersByDiscrim) { return kj::strTree(index); }, ", "),
   2793             "};\n"),
   2794         brandDeps.size() == 0 ? kj::strTree() : kj::strTree(
   2795             "KJ_CONSTEXPR(const) ::capnp::_::RawBrandedSchema::Dependency bd_", hexId, "[] = ",
   2796             kj::mv(brandDeps), ";\n"),
   2797         "const ::capnp::_::RawSchema s_", hexId, " = {\n"
   2798         "  0x", hexId, ", b_", hexId, ".words, ", rawSchema.size(), ", ",
   2799         deps.size() == 0 ? kj::strTree("nullptr") : kj::strTree("d_", hexId), ", ",
   2800         membersByName.size() == 0 ? kj::strTree("nullptr") : kj::strTree("m_", hexId), ",\n",
   2801         "  ", deps.size(), ", ", membersByName.size(), ", ",
   2802         membersByDiscrim.size() == 0 ? kj::strTree("nullptr") : kj::strTree("i_", hexId),
   2803         ", nullptr, nullptr, { &s_", hexId, ", nullptr, ",
   2804         brandDeps.size() == 0 ? kj::strTree("nullptr, 0, 0") : kj::strTree(
   2805             "bd_", hexId, ", 0, " "sizeof(bd_", hexId, ") / sizeof(bd_", hexId, "[0])"),
   2806         ", nullptr }\n"
   2807         "};\n"
   2808         "#endif  // !CAPNP_LITE\n");
   2809 
   2810     NodeText top = makeNodeTextWithoutNested(
   2811         namespace_, scope, name, schema,
   2812         KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDecl); },
   2813         templateContext);
   2814 
   2815     NodeText result = {
   2816       kj::mv(top.outerTypeDecl),
   2817 
   2818       kj::strTree(
   2819           kj::mv(top.outerTypeDef),
   2820           KJ_MAP(n, nestedTexts) { return kj::mv(n.outerTypeDef); }),
   2821 
   2822       kj::strTree(
   2823           kj::mv(top.readerBuilderDefs),
   2824           KJ_MAP(n, nestedTexts) { return kj::mv(n.readerBuilderDefs); }),
   2825 
   2826       kj::strTree(
   2827           kj::mv(top.inlineMethodDefs),
   2828           KJ_MAP(n, nestedTexts) { return kj::mv(n.inlineMethodDefs); }),
   2829 
   2830       kj::strTree(
   2831           kj::mv(schemaDecl),
   2832           kj::mv(top.capnpSchemaDecls),
   2833           KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDecls); }),
   2834 
   2835       kj::strTree(
   2836           kj::mv(schemaDef),
   2837           kj::mv(top.capnpSchemaDefs),
   2838           KJ_MAP(n, nestedTexts) { return kj::mv(n.capnpSchemaDefs); }),
   2839 
   2840       kj::strTree(
   2841           kj::mv(top.sourceFileDefs),
   2842           KJ_MAP(n, nestedTexts) { return kj::mv(n.sourceFileDefs); }),
   2843     };
   2844 
   2845     if (templateContext.isGeneric()) {
   2846       // This is a template, so move all source declarations into the header.
   2847       result.inlineMethodDefs = kj::strTree(
   2848           kj::mv(result.inlineMethodDefs), kj::mv(result.sourceFileDefs));
   2849       result.sourceFileDefs = kj::strTree();
   2850     }
   2851 
   2852     return result;
   2853   }
   2854 
   2855   NodeText makeNodeTextWithoutNested(kj::StringPtr namespace_, kj::StringPtr scope,
   2856                                      kj::StringPtr name, Schema schema,
   2857                                      kj::Array<kj::StringTree> nestedTypeDecls,
   2858                                      const TemplateContext& templateContext) {
   2859     auto proto = schema.getProto();
   2860     KJ_IF_MAYBE(annotatedName, annotationValue(proto, NAME_ANNOTATION_ID)) {
   2861       name = annotatedName->getText();
   2862     }
   2863     auto hexId = kj::hex(proto.getId());
   2864 
   2865     switch (proto.which()) {
   2866       case schema::Node::FILE:
   2867         KJ_FAIL_REQUIRE("This method shouldn't be called on file nodes.");
   2868 
   2869       case schema::Node::STRUCT: {
   2870         StructText structText =
   2871             makeStructText(scope, name, schema.asStruct(), kj::mv(nestedTypeDecls),
   2872                            templateContext);
   2873 
   2874         return NodeText {
   2875           kj::mv(structText.outerTypeDecl),
   2876           kj::mv(structText.outerTypeDef),
   2877           kj::mv(structText.readerBuilderDefs),
   2878           kj::mv(structText.inlineMethodDefs),
   2879 
   2880           kj::strTree(),
   2881           kj::strTree(),
   2882 
   2883           kj::mv(structText.sourceDefs),
   2884         };
   2885       }
   2886 
   2887       case schema::Node::ENUM: {
   2888         auto enumerants = schema.asEnum().getEnumerants();
   2889 
   2890         return NodeText {
   2891           scope.size() == 0 ? kj::strTree() : kj::strTree(
   2892               "  typedef ::capnp::schemas::", name, "_", hexId, " ", name, ";\n"
   2893               "\n"),
   2894 
   2895           scope.size() > 0 ? kj::strTree() : kj::strTree(
   2896               "typedef ::capnp::schemas::", name, "_", hexId, " ", name, ";\n"
   2897               "\n"),
   2898 
   2899           kj::strTree(),
   2900           kj::strTree(),
   2901 
   2902           kj::strTree(
   2903               // We declare enums in the capnp::schemas namespace and then typedef them into
   2904               // place because we don't want them to be parameterized for generics.
   2905               "enum class ", name, "_", hexId, ": uint16_t {\n",
   2906               KJ_MAP(e, enumerants) {
   2907                 return kj::strTree("  ", toUpperCase(protoName(e.getProto())), ",\n");
   2908               },
   2909               "};\n"
   2910               "CAPNP_DECLARE_ENUM(", name, ", ", hexId, ");\n"),
   2911           kj::strTree(
   2912               "CAPNP_DEFINE_ENUM(", name, "_", hexId, ", ", hexId, ");\n"),
   2913 
   2914           kj::strTree(),
   2915         };
   2916       }
   2917 
   2918       case schema::Node::INTERFACE: {
   2919         hasInterfaces = true;
   2920 
   2921         InterfaceText interfaceText =
   2922             makeInterfaceText(scope, name, schema.asInterface(), kj::mv(nestedTypeDecls),
   2923                               templateContext);
   2924 
   2925         return NodeText {
   2926           kj::mv(interfaceText.outerTypeDecl),
   2927           kj::mv(interfaceText.outerTypeDef),
   2928           kj::mv(interfaceText.clientServerDefs),
   2929           kj::mv(interfaceText.inlineMethodDefs),
   2930 
   2931           kj::strTree(),
   2932           kj::strTree(),
   2933 
   2934           kj::mv(interfaceText.sourceDefs),
   2935         };
   2936       }
   2937 
   2938       case schema::Node::CONST: {
   2939         auto constText = makeConstText(scope, name, schema.asConst(), templateContext);
   2940 
   2941         return NodeText {
   2942           scope.size() == 0 ? kj::strTree() : kj::strTree("  ", kj::mv(constText.decl)),
   2943           scope.size() > 0 ? kj::strTree() : kj::mv(constText.decl),
   2944           kj::strTree(),
   2945           kj::strTree(),
   2946 
   2947           kj::strTree(),
   2948           kj::strTree(),
   2949 
   2950           kj::mv(constText.def),
   2951         };
   2952       }
   2953 
   2954       case schema::Node::ANNOTATION: {
   2955         return NodeText {
   2956           kj::strTree(),
   2957           kj::strTree(),
   2958           kj::strTree(),
   2959           kj::strTree(),
   2960 
   2961           kj::strTree(),
   2962           kj::strTree(),
   2963 
   2964           kj::strTree(),
   2965         };
   2966       }
   2967     }
   2968 
   2969     KJ_UNREACHABLE;
   2970   }
   2971 
   2972   // -----------------------------------------------------------------
   2973 
   2974   struct FileText {
   2975     kj::StringTree header;
   2976     kj::StringTree source;
   2977   };
   2978 
   2979   FileText makeFileText(Schema schema,
   2980                         schema::CodeGeneratorRequest::RequestedFile::Reader request) {
   2981     usedImports.clear();
   2982 
   2983     auto node = schema.getProto();
   2984     auto displayName = node.getDisplayName();
   2985 
   2986     kj::Vector<kj::ArrayPtr<const char>> namespaceParts;
   2987     kj::String namespacePrefix;
   2988 
   2989     for (auto annotation: node.getAnnotations()) {
   2990       if (annotation.getId() == NAMESPACE_ANNOTATION_ID) {
   2991         kj::StringPtr ns = annotation.getValue().getText();
   2992         kj::StringPtr ns2 = ns;
   2993         namespacePrefix = kj::str("::", ns);
   2994 
   2995         for (;;) {
   2996           KJ_IF_MAYBE(colonPos, ns.findFirst(':')) {
   2997             namespaceParts.add(ns.slice(0, *colonPos));
   2998             ns = ns.slice(*colonPos);
   2999             if (!ns.startsWith("::")) {
   3000               context.exitError(kj::str(displayName, ": invalid namespace spec: ", ns2));
   3001             }
   3002             ns = ns.slice(2);
   3003           } else {
   3004             namespaceParts.add(ns);
   3005             break;
   3006           }
   3007         }
   3008 
   3009         break;
   3010       }
   3011     }
   3012 
   3013     auto nodeTexts = KJ_MAP(nested, node.getNestedNodes()) {
   3014       return makeNodeText(namespacePrefix, "", nested.getName(),
   3015                           schemaLoader.getUnbound(nested.getId()), TemplateContext());
   3016     };
   3017 
   3018     kj::String separator = kj::str("// ", kj::repeat('=', 87), "\n");
   3019 
   3020     kj::Vector<kj::StringPtr> includes;
   3021     for (auto import: request.getImports()) {
   3022       if (usedImports.count(import.getId()) > 0) {
   3023         includes.add(import.getName());
   3024       }
   3025     }
   3026 
   3027     kj::StringTree sourceDefs = kj::strTree(
   3028         KJ_MAP(n, nodeTexts) { return kj::mv(n.sourceFileDefs); });
   3029 
   3030     return FileText {
   3031       kj::strTree(
   3032           "// Generated by Cap'n Proto compiler, DO NOT EDIT\n"
   3033           "// source: ", baseName(displayName), "\n"
   3034           "\n"
   3035           "#pragma once\n"
   3036           "\n"
   3037           "#include <capnp/generated-header-support.h>\n"
   3038           "#include <kj/windows-sanity.h>\n",  // work-around macro conflict with VOID
   3039           hasInterfaces ? kj::strTree(
   3040             "#if !CAPNP_LITE\n"
   3041             "#include <capnp/capability.h>\n"
   3042             "#endif  // !CAPNP_LITE\n"
   3043           ) : kj::strTree(),
   3044           "\n"
   3045           "#if CAPNP_VERSION != ", CAPNP_VERSION, "\n"
   3046           "#error \"Version mismatch between generated code and library headers.  You must "
   3047               "use the same version of the Cap'n Proto compiler and library.\"\n"
   3048           "#endif\n"
   3049           "\n",
   3050           KJ_MAP(path, includes) {
   3051             if (path.startsWith("/")) {
   3052               return kj::strTree("#include <", path.slice(1), ".h>\n");
   3053             } else {
   3054               return kj::strTree("#include \"", path, ".h\"\n");
   3055             }
   3056           },
   3057           "\n"
   3058           "CAPNP_BEGIN_HEADER\n"
   3059           "\n"
   3060           "namespace capnp {\n"
   3061           "namespace schemas {\n"
   3062           "\n",
   3063           KJ_MAP(n, nodeTexts) { return kj::mv(n.capnpSchemaDecls); },
   3064           "\n"
   3065           "}  // namespace schemas\n"
   3066           "}  // namespace capnp\n"
   3067           "\n",
   3068 
   3069           KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n",
   3070           KJ_MAP(n, nodeTexts) { return kj::mv(n.outerTypeDef); },
   3071           separator, "\n",
   3072           KJ_MAP(n, nodeTexts) { return kj::mv(n.readerBuilderDefs); },
   3073           separator, "\n",
   3074           KJ_MAP(n, nodeTexts) { return kj::mv(n.inlineMethodDefs); },
   3075           KJ_MAP(n, namespaceParts) { return kj::strTree("}  // namespace\n"); },
   3076           "\n"
   3077           "CAPNP_END_HEADER\n"
   3078           "\n"),
   3079 
   3080       kj::strTree(
   3081           "// Generated by Cap'n Proto compiler, DO NOT EDIT\n"
   3082           "// source: ", baseName(displayName), "\n"
   3083           "\n"
   3084           "#include \"", baseName(displayName), ".h\"\n"
   3085           "\n"
   3086           "namespace capnp {\n"
   3087           "namespace schemas {\n",
   3088           KJ_MAP(n, nodeTexts) { return kj::mv(n.capnpSchemaDefs); },
   3089           "}  // namespace schemas\n"
   3090           "}  // namespace capnp\n",
   3091           sourceDefs.size() == 0 ? kj::strTree() : kj::strTree(
   3092               "\n", separator, "\n",
   3093               KJ_MAP(n, namespaceParts) { return kj::strTree("namespace ", n, " {\n"); }, "\n",
   3094               kj::mv(sourceDefs), "\n",
   3095               KJ_MAP(n, namespaceParts) { return kj::strTree("}  // namespace\n"); }, "\n"))
   3096     };
   3097   }
   3098 
   3099   // -----------------------------------------------------------------
   3100 
   3101   kj::Own<kj::Filesystem> fs = kj::newDiskFilesystem();
   3102 
   3103   void writeFile(kj::StringPtr filename, const kj::StringTree& text) {
   3104     // We don't use replaceFile() here because atomic replacements are actually detrimental for
   3105     // build tools:
   3106     // - It's the responsibility of the build pipeline to ensure that no one else is concurrently
   3107     //   reading the file when we write it, so atomicity brings no benefit.
   3108     // - Atomic replacements force disk syncs which could slow us down for no benefit at all.
   3109     // - Opening the existing file and overwriting it may allow the filesystem to reuse
   3110     //   already-allocated blocks, or maybe even notice that no actual changes occurred.
   3111     // - In a power outage scenario, the user would obviously restart the build from scratch
   3112     //   anyway.
   3113     //
   3114     // At one point, in a fit of over-engineering, we used writable mmap() here. That turned out
   3115     // to be a bad idea: writable mmap() is not implemented on some filesystems, especially shared
   3116     // folders in VirtualBox. Oh well.
   3117 
   3118     auto path = kj::Path::parse(filename);
   3119     auto file = fs->getCurrent().openFile(path,
   3120         kj::WriteMode::CREATE | kj::WriteMode::MODIFY | kj::WriteMode::CREATE_PARENT);
   3121     file->writeAll(text.flatten());
   3122   }
   3123 
   3124   kj::MainBuilder::Validity run() {
   3125     ReaderOptions options;
   3126     options.traversalLimitInWords = 1 << 30;  // Don't limit.
   3127     StreamFdMessageReader reader(0, options);
   3128     auto request = reader.getRoot<schema::CodeGeneratorRequest>();
   3129 
   3130     auto capnpVersion = request.getCapnpVersion();
   3131 
   3132     if (capnpVersion.getMajor() != CAPNP_VERSION_MAJOR ||
   3133         capnpVersion.getMinor() != CAPNP_VERSION_MINOR ||
   3134         capnpVersion.getMicro() != CAPNP_VERSION_MICRO) {
   3135       auto compilerVersion = request.hasCapnpVersion()
   3136           ? kj::str(capnpVersion.getMajor(), '.', capnpVersion.getMinor(), '.',
   3137                     capnpVersion.getMicro())
   3138           : kj::str("pre-0.6");  // pre-0.6 didn't send the version.
   3139       auto generatorVersion = kj::str(
   3140           CAPNP_VERSION_MAJOR, '.', CAPNP_VERSION_MINOR, '.', CAPNP_VERSION_MICRO);
   3141 
   3142       KJ_LOG(WARNING,
   3143           "You appear to be using different versions of 'capnp' (the compiler) and "
   3144           "'capnpc-c++' (the code generator). This can happen, for example, if you built "
   3145           "a custom version of 'capnp' but then ran it with '-oc++', which invokes "
   3146           "'capnpc-c++' from your PATH (i.e. the installed version). To specify an alternate "
   3147           "'capnpc-c++' executable, try something like '-o/path/to/capnpc-c++' instead.",
   3148           compilerVersion, generatorVersion);
   3149     }
   3150 
   3151     for (auto node: request.getNodes()) {
   3152       schemaLoader.load(node);
   3153     }
   3154 
   3155     for (auto requestedFile: request.getRequestedFiles()) {
   3156       auto schema = schemaLoader.get(requestedFile.getId());
   3157       auto fileText = makeFileText(schema, requestedFile);
   3158 
   3159       writeFile(kj::str(schema.getProto().getDisplayName(), ".h"), fileText.header);
   3160       writeFile(kj::str(schema.getProto().getDisplayName(), ".c++"), fileText.source);
   3161     }
   3162 
   3163     return true;
   3164   }
   3165 };
   3166 
   3167 }  // namespace
   3168 }  // namespace capnp
   3169 
   3170 KJ_MAIN(capnp::CapnpcCppMain);