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

addressbook.c++ (9674B)


      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 sample code appears in the documentation for the C++ implementation.
     23 //
     24 // If Cap'n Proto is installed, build the sample like:
     25 //   capnp compile -oc++ addressbook.capnp
     26 //   c++ -std=c++14 -Wall addressbook.c++ addressbook.capnp.c++ `pkg-config --cflags --libs capnp` -o addressbook
     27 //
     28 // If Cap'n Proto is not installed, but the source is located at $SRC and has been
     29 // compiled in $BUILD (often both are simply ".." from here), you can do:
     30 //   $BUILD/capnp compile -I$SRC/src -o$BUILD/capnpc-c++ addressbook.capnp
     31 //   c++ -std=c++14 -Wall addressbook.c++ addressbook.capnp.c++ -I$SRC/src -L$BUILD/.libs -lcapnp -lkj -o addressbook
     32 //
     33 // Run like:
     34 //   ./addressbook write | ./addressbook read
     35 // Use "dwrite" and "dread" to use dynamic code instead.
     36 
     37 // TODO(test):  Needs cleanup.
     38 
     39 #include "addressbook.capnp.h"
     40 #include <capnp/message.h>
     41 #include <capnp/serialize-packed.h>
     42 #include <iostream>
     43 
     44 using addressbook::Person;
     45 using addressbook::AddressBook;
     46 
     47 void writeAddressBook(int fd) {
     48   ::capnp::MallocMessageBuilder message;
     49 
     50   AddressBook::Builder addressBook = message.initRoot<AddressBook>();
     51   ::capnp::List<Person>::Builder people = addressBook.initPeople(2);
     52 
     53   Person::Builder alice = people[0];
     54   alice.setId(123);
     55   alice.setName("Alice");
     56   alice.setEmail("alice@example.com");
     57   // Type shown for explanation purposes; normally you'd use auto.
     58   ::capnp::List<Person::PhoneNumber>::Builder alicePhones =
     59       alice.initPhones(1);
     60   alicePhones[0].setNumber("555-1212");
     61   alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE);
     62   alice.getEmployment().setSchool("MIT");
     63 
     64   Person::Builder bob = people[1];
     65   bob.setId(456);
     66   bob.setName("Bob");
     67   bob.setEmail("bob@example.com");
     68   auto bobPhones = bob.initPhones(2);
     69   bobPhones[0].setNumber("555-4567");
     70   bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
     71   bobPhones[1].setNumber("555-7654");
     72   bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
     73   bob.getEmployment().setUnemployed();
     74 
     75   writePackedMessageToFd(fd, message);
     76 }
     77 
     78 void printAddressBook(int fd) {
     79   ::capnp::PackedFdMessageReader message(fd);
     80 
     81   AddressBook::Reader addressBook = message.getRoot<AddressBook>();
     82 
     83   for (Person::Reader person : addressBook.getPeople()) {
     84     std::cout << person.getName().cStr() << ": "
     85               << person.getEmail().cStr() << std::endl;
     86     for (Person::PhoneNumber::Reader phone: person.getPhones()) {
     87       const char* typeName = "UNKNOWN";
     88       switch (phone.getType()) {
     89         case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break;
     90         case Person::PhoneNumber::Type::HOME: typeName = "home"; break;
     91         case Person::PhoneNumber::Type::WORK: typeName = "work"; break;
     92       }
     93       std::cout << "  " << typeName << " phone: "
     94                 << phone.getNumber().cStr() << std::endl;
     95     }
     96     Person::Employment::Reader employment = person.getEmployment();
     97     switch (employment.which()) {
     98       case Person::Employment::UNEMPLOYED:
     99         std::cout << "  unemployed" << std::endl;
    100         break;
    101       case Person::Employment::EMPLOYER:
    102         std::cout << "  employer: "
    103                   << employment.getEmployer().cStr() << std::endl;
    104         break;
    105       case Person::Employment::SCHOOL:
    106         std::cout << "  student at: "
    107                   << employment.getSchool().cStr() << std::endl;
    108         break;
    109       case Person::Employment::SELF_EMPLOYED:
    110         std::cout << "  self-employed" << std::endl;
    111         break;
    112     }
    113   }
    114 }
    115 
    116 #if !CAPNP_LITE
    117 
    118 #include "addressbook.capnp.h"
    119 #include <capnp/message.h>
    120 #include <capnp/serialize-packed.h>
    121 #include <iostream>
    122 #include <capnp/schema.h>
    123 #include <capnp/dynamic.h>
    124 
    125 using ::capnp::DynamicValue;
    126 using ::capnp::DynamicStruct;
    127 using ::capnp::DynamicEnum;
    128 using ::capnp::DynamicList;
    129 using ::capnp::List;
    130 using ::capnp::Schema;
    131 using ::capnp::StructSchema;
    132 using ::capnp::EnumSchema;
    133 
    134 using ::capnp::Void;
    135 using ::capnp::Text;
    136 using ::capnp::MallocMessageBuilder;
    137 using ::capnp::PackedFdMessageReader;
    138 
    139 void dynamicWriteAddressBook(int fd, StructSchema schema) {
    140   // Write a message using the dynamic API to set each
    141   // field by text name.  This isn't something you'd
    142   // normally want to do; it's just for illustration.
    143 
    144   MallocMessageBuilder message;
    145 
    146   // Types shown for explanation purposes; normally you'd
    147   // use auto.
    148   DynamicStruct::Builder addressBook =
    149       message.initRoot<DynamicStruct>(schema);
    150 
    151   DynamicList::Builder people =
    152       addressBook.init("people", 2).as<DynamicList>();
    153 
    154   DynamicStruct::Builder alice =
    155       people[0].as<DynamicStruct>();
    156   alice.set("id", 123);
    157   alice.set("name", "Alice");
    158   alice.set("email", "alice@example.com");
    159   auto alicePhones = alice.init("phones", 1).as<DynamicList>();
    160   auto phone0 = alicePhones[0].as<DynamicStruct>();
    161   phone0.set("number", "555-1212");
    162   phone0.set("type", "mobile");
    163   alice.get("employment").as<DynamicStruct>()
    164        .set("school", "MIT");
    165 
    166   auto bob = people[1].as<DynamicStruct>();
    167   bob.set("id", 456);
    168   bob.set("name", "Bob");
    169   bob.set("email", "bob@example.com");
    170 
    171   // Some magic:  We can convert a dynamic sub-value back to
    172   // the native type with as<T>()!
    173   List<Person::PhoneNumber>::Builder bobPhones =
    174       bob.init("phones", 2).as<List<Person::PhoneNumber>>();
    175   bobPhones[0].setNumber("555-4567");
    176   bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
    177   bobPhones[1].setNumber("555-7654");
    178   bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
    179   bob.get("employment").as<DynamicStruct>()
    180      .set("unemployed", ::capnp::VOID);
    181 
    182   writePackedMessageToFd(fd, message);
    183 }
    184 
    185 void dynamicPrintValue(DynamicValue::Reader value) {
    186   // Print an arbitrary message via the dynamic API by
    187   // iterating over the schema.  Look at the handling
    188   // of STRUCT in particular.
    189 
    190   switch (value.getType()) {
    191     case DynamicValue::VOID:
    192       std::cout << "";
    193       break;
    194     case DynamicValue::BOOL:
    195       std::cout << (value.as<bool>() ? "true" : "false");
    196       break;
    197     case DynamicValue::INT:
    198       std::cout << value.as<int64_t>();
    199       break;
    200     case DynamicValue::UINT:
    201       std::cout << value.as<uint64_t>();
    202       break;
    203     case DynamicValue::FLOAT:
    204       std::cout << value.as<double>();
    205       break;
    206     case DynamicValue::TEXT:
    207       std::cout << '\"' << value.as<Text>().cStr() << '\"';
    208       break;
    209     case DynamicValue::LIST: {
    210       std::cout << "[";
    211       bool first = true;
    212       for (auto element: value.as<DynamicList>()) {
    213         if (first) {
    214           first = false;
    215         } else {
    216           std::cout << ", ";
    217         }
    218         dynamicPrintValue(element);
    219       }
    220       std::cout << "]";
    221       break;
    222     }
    223     case DynamicValue::ENUM: {
    224       auto enumValue = value.as<DynamicEnum>();
    225       KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) {
    226         std::cout <<
    227             enumerant->getProto().getName().cStr();
    228       } else {
    229         // Unknown enum value; output raw number.
    230         std::cout << enumValue.getRaw();
    231       }
    232       break;
    233     }
    234     case DynamicValue::STRUCT: {
    235       std::cout << "(";
    236       auto structValue = value.as<DynamicStruct>();
    237       bool first = true;
    238       for (auto field: structValue.getSchema().getFields()) {
    239         if (!structValue.has(field)) continue;
    240         if (first) {
    241           first = false;
    242         } else {
    243           std::cout << ", ";
    244         }
    245         std::cout << field.getProto().getName().cStr()
    246                   << " = ";
    247         dynamicPrintValue(structValue.get(field));
    248       }
    249       std::cout << ")";
    250       break;
    251     }
    252     default:
    253       // There are other types, we aren't handling them.
    254       std::cout << "?";
    255       break;
    256   }
    257 }
    258 
    259 void dynamicPrintMessage(int fd, StructSchema schema) {
    260   PackedFdMessageReader message(fd);
    261   dynamicPrintValue(message.getRoot<DynamicStruct>(schema));
    262   std::cout << std::endl;
    263 }
    264 
    265 #endif  // !CAPNP_LITE
    266 
    267 int main(int argc, char* argv[]) {
    268   if (argc != 2) {
    269     std::cerr << "Missing arg." << std::endl;
    270     return 1;
    271   } else if (strcmp(argv[1], "write") == 0) {
    272     writeAddressBook(1);
    273   } else if (strcmp(argv[1], "read") == 0) {
    274     printAddressBook(0);
    275 #if !CAPNP_LITE
    276   } else if (strcmp(argv[1], "dwrite") == 0) {
    277     StructSchema schema = Schema::from<AddressBook>();
    278     dynamicWriteAddressBook(1, schema);
    279   } else if (strcmp(argv[1], "dread") == 0) {
    280     StructSchema schema = Schema::from<AddressBook>();
    281     dynamicPrintMessage(0, schema);
    282 #endif
    283   } else {
    284     std::cerr << "Invalid arg: " << argv[1] << std::endl;
    285     return 1;
    286   }
    287   return 0;
    288 }
    289