annotate src/capnproto-0.6.0/c++/samples/addressbook.c++ @ 147:45360b968bf4

Cap'n Proto v0.6 + build for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 22 May 2017 10:01:37 +0100
parents
children
rev   line source
cannam@147 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@147 2 // Licensed under the MIT License:
cannam@147 3 //
cannam@147 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@147 5 // of this software and associated documentation files (the "Software"), to deal
cannam@147 6 // in the Software without restriction, including without limitation the rights
cannam@147 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@147 8 // copies of the Software, and to permit persons to whom the Software is
cannam@147 9 // furnished to do so, subject to the following conditions:
cannam@147 10 //
cannam@147 11 // The above copyright notice and this permission notice shall be included in
cannam@147 12 // all copies or substantial portions of the Software.
cannam@147 13 //
cannam@147 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@147 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@147 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@147 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@147 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@147 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@147 20 // THE SOFTWARE.
cannam@147 21
cannam@147 22 // This sample code appears in the documentation for the C++ implementation.
cannam@147 23 //
cannam@147 24 // If Cap'n Proto is installed, build the sample like:
cannam@147 25 // capnp compile -oc++ addressbook.capnp
cannam@147 26 // c++ -std=c++11 -Wall addressbook.c++ addressbook.capnp.c++ `pkg-config --cflags --libs capnp` -o addressbook
cannam@147 27 //
cannam@147 28 // If Cap'n Proto is not installed, but the source is located at $SRC and has been
cannam@147 29 // compiled in $BUILD (often both are simply ".." from here), you can do:
cannam@147 30 // $BUILD/capnp compile -I$SRC/src -o$BUILD/capnpc-c++ addressbook.capnp
cannam@147 31 // c++ -std=c++11 -Wall addressbook.c++ addressbook.capnp.c++ -I$SRC/src -L$BUILD/.libs -lcapnp -lkj -o addressbook
cannam@147 32 //
cannam@147 33 // Run like:
cannam@147 34 // ./addressbook write | ./addressbook read
cannam@147 35 // Use "dwrite" and "dread" to use dynamic code instead.
cannam@147 36
cannam@147 37 // TODO(test): Needs cleanup.
cannam@147 38
cannam@147 39 #include "addressbook.capnp.h"
cannam@147 40 #include <capnp/message.h>
cannam@147 41 #include <capnp/serialize-packed.h>
cannam@147 42 #include <iostream>
cannam@147 43
cannam@147 44 using addressbook::Person;
cannam@147 45 using addressbook::AddressBook;
cannam@147 46
cannam@147 47 void writeAddressBook(int fd) {
cannam@147 48 ::capnp::MallocMessageBuilder message;
cannam@147 49
cannam@147 50 AddressBook::Builder addressBook = message.initRoot<AddressBook>();
cannam@147 51 ::capnp::List<Person>::Builder people = addressBook.initPeople(2);
cannam@147 52
cannam@147 53 Person::Builder alice = people[0];
cannam@147 54 alice.setId(123);
cannam@147 55 alice.setName("Alice");
cannam@147 56 alice.setEmail("alice@example.com");
cannam@147 57 // Type shown for explanation purposes; normally you'd use auto.
cannam@147 58 ::capnp::List<Person::PhoneNumber>::Builder alicePhones =
cannam@147 59 alice.initPhones(1);
cannam@147 60 alicePhones[0].setNumber("555-1212");
cannam@147 61 alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE);
cannam@147 62 alice.getEmployment().setSchool("MIT");
cannam@147 63
cannam@147 64 Person::Builder bob = people[1];
cannam@147 65 bob.setId(456);
cannam@147 66 bob.setName("Bob");
cannam@147 67 bob.setEmail("bob@example.com");
cannam@147 68 auto bobPhones = bob.initPhones(2);
cannam@147 69 bobPhones[0].setNumber("555-4567");
cannam@147 70 bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
cannam@147 71 bobPhones[1].setNumber("555-7654");
cannam@147 72 bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
cannam@147 73 bob.getEmployment().setUnemployed();
cannam@147 74
cannam@147 75 writePackedMessageToFd(fd, message);
cannam@147 76 }
cannam@147 77
cannam@147 78 void printAddressBook(int fd) {
cannam@147 79 ::capnp::PackedFdMessageReader message(fd);
cannam@147 80
cannam@147 81 AddressBook::Reader addressBook = message.getRoot<AddressBook>();
cannam@147 82
cannam@147 83 for (Person::Reader person : addressBook.getPeople()) {
cannam@147 84 std::cout << person.getName().cStr() << ": "
cannam@147 85 << person.getEmail().cStr() << std::endl;
cannam@147 86 for (Person::PhoneNumber::Reader phone: person.getPhones()) {
cannam@147 87 const char* typeName = "UNKNOWN";
cannam@147 88 switch (phone.getType()) {
cannam@147 89 case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break;
cannam@147 90 case Person::PhoneNumber::Type::HOME: typeName = "home"; break;
cannam@147 91 case Person::PhoneNumber::Type::WORK: typeName = "work"; break;
cannam@147 92 }
cannam@147 93 std::cout << " " << typeName << " phone: "
cannam@147 94 << phone.getNumber().cStr() << std::endl;
cannam@147 95 }
cannam@147 96 Person::Employment::Reader employment = person.getEmployment();
cannam@147 97 switch (employment.which()) {
cannam@147 98 case Person::Employment::UNEMPLOYED:
cannam@147 99 std::cout << " unemployed" << std::endl;
cannam@147 100 break;
cannam@147 101 case Person::Employment::EMPLOYER:
cannam@147 102 std::cout << " employer: "
cannam@147 103 << employment.getEmployer().cStr() << std::endl;
cannam@147 104 break;
cannam@147 105 case Person::Employment::SCHOOL:
cannam@147 106 std::cout << " student at: "
cannam@147 107 << employment.getSchool().cStr() << std::endl;
cannam@147 108 break;
cannam@147 109 case Person::Employment::SELF_EMPLOYED:
cannam@147 110 std::cout << " self-employed" << std::endl;
cannam@147 111 break;
cannam@147 112 }
cannam@147 113 }
cannam@147 114 }
cannam@147 115
cannam@147 116 #include "addressbook.capnp.h"
cannam@147 117 #include <capnp/message.h>
cannam@147 118 #include <capnp/serialize-packed.h>
cannam@147 119 #include <iostream>
cannam@147 120 #include <capnp/schema.h>
cannam@147 121 #include <capnp/dynamic.h>
cannam@147 122
cannam@147 123 using ::capnp::DynamicValue;
cannam@147 124 using ::capnp::DynamicStruct;
cannam@147 125 using ::capnp::DynamicEnum;
cannam@147 126 using ::capnp::DynamicList;
cannam@147 127 using ::capnp::List;
cannam@147 128 using ::capnp::Schema;
cannam@147 129 using ::capnp::StructSchema;
cannam@147 130 using ::capnp::EnumSchema;
cannam@147 131
cannam@147 132 using ::capnp::Void;
cannam@147 133 using ::capnp::Text;
cannam@147 134 using ::capnp::MallocMessageBuilder;
cannam@147 135 using ::capnp::PackedFdMessageReader;
cannam@147 136
cannam@147 137 void dynamicWriteAddressBook(int fd, StructSchema schema) {
cannam@147 138 // Write a message using the dynamic API to set each
cannam@147 139 // field by text name. This isn't something you'd
cannam@147 140 // normally want to do; it's just for illustration.
cannam@147 141
cannam@147 142 MallocMessageBuilder message;
cannam@147 143
cannam@147 144 // Types shown for explanation purposes; normally you'd
cannam@147 145 // use auto.
cannam@147 146 DynamicStruct::Builder addressBook =
cannam@147 147 message.initRoot<DynamicStruct>(schema);
cannam@147 148
cannam@147 149 DynamicList::Builder people =
cannam@147 150 addressBook.init("people", 2).as<DynamicList>();
cannam@147 151
cannam@147 152 DynamicStruct::Builder alice =
cannam@147 153 people[0].as<DynamicStruct>();
cannam@147 154 alice.set("id", 123);
cannam@147 155 alice.set("name", "Alice");
cannam@147 156 alice.set("email", "alice@example.com");
cannam@147 157 auto alicePhones = alice.init("phones", 1).as<DynamicList>();
cannam@147 158 auto phone0 = alicePhones[0].as<DynamicStruct>();
cannam@147 159 phone0.set("number", "555-1212");
cannam@147 160 phone0.set("type", "mobile");
cannam@147 161 alice.get("employment").as<DynamicStruct>()
cannam@147 162 .set("school", "MIT");
cannam@147 163
cannam@147 164 auto bob = people[1].as<DynamicStruct>();
cannam@147 165 bob.set("id", 456);
cannam@147 166 bob.set("name", "Bob");
cannam@147 167 bob.set("email", "bob@example.com");
cannam@147 168
cannam@147 169 // Some magic: We can convert a dynamic sub-value back to
cannam@147 170 // the native type with as<T>()!
cannam@147 171 List<Person::PhoneNumber>::Builder bobPhones =
cannam@147 172 bob.init("phones", 2).as<List<Person::PhoneNumber>>();
cannam@147 173 bobPhones[0].setNumber("555-4567");
cannam@147 174 bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
cannam@147 175 bobPhones[1].setNumber("555-7654");
cannam@147 176 bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
cannam@147 177 bob.get("employment").as<DynamicStruct>()
cannam@147 178 .set("unemployed", ::capnp::VOID);
cannam@147 179
cannam@147 180 writePackedMessageToFd(fd, message);
cannam@147 181 }
cannam@147 182
cannam@147 183 void dynamicPrintValue(DynamicValue::Reader value) {
cannam@147 184 // Print an arbitrary message via the dynamic API by
cannam@147 185 // iterating over the schema. Look at the handling
cannam@147 186 // of STRUCT in particular.
cannam@147 187
cannam@147 188 switch (value.getType()) {
cannam@147 189 case DynamicValue::VOID:
cannam@147 190 std::cout << "";
cannam@147 191 break;
cannam@147 192 case DynamicValue::BOOL:
cannam@147 193 std::cout << (value.as<bool>() ? "true" : "false");
cannam@147 194 break;
cannam@147 195 case DynamicValue::INT:
cannam@147 196 std::cout << value.as<int64_t>();
cannam@147 197 break;
cannam@147 198 case DynamicValue::UINT:
cannam@147 199 std::cout << value.as<uint64_t>();
cannam@147 200 break;
cannam@147 201 case DynamicValue::FLOAT:
cannam@147 202 std::cout << value.as<double>();
cannam@147 203 break;
cannam@147 204 case DynamicValue::TEXT:
cannam@147 205 std::cout << '\"' << value.as<Text>().cStr() << '\"';
cannam@147 206 break;
cannam@147 207 case DynamicValue::LIST: {
cannam@147 208 std::cout << "[";
cannam@147 209 bool first = true;
cannam@147 210 for (auto element: value.as<DynamicList>()) {
cannam@147 211 if (first) {
cannam@147 212 first = false;
cannam@147 213 } else {
cannam@147 214 std::cout << ", ";
cannam@147 215 }
cannam@147 216 dynamicPrintValue(element);
cannam@147 217 }
cannam@147 218 std::cout << "]";
cannam@147 219 break;
cannam@147 220 }
cannam@147 221 case DynamicValue::ENUM: {
cannam@147 222 auto enumValue = value.as<DynamicEnum>();
cannam@147 223 KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) {
cannam@147 224 std::cout <<
cannam@147 225 enumerant->getProto().getName().cStr();
cannam@147 226 } else {
cannam@147 227 // Unknown enum value; output raw number.
cannam@147 228 std::cout << enumValue.getRaw();
cannam@147 229 }
cannam@147 230 break;
cannam@147 231 }
cannam@147 232 case DynamicValue::STRUCT: {
cannam@147 233 std::cout << "(";
cannam@147 234 auto structValue = value.as<DynamicStruct>();
cannam@147 235 bool first = true;
cannam@147 236 for (auto field: structValue.getSchema().getFields()) {
cannam@147 237 if (!structValue.has(field)) continue;
cannam@147 238 if (first) {
cannam@147 239 first = false;
cannam@147 240 } else {
cannam@147 241 std::cout << ", ";
cannam@147 242 }
cannam@147 243 std::cout << field.getProto().getName().cStr()
cannam@147 244 << " = ";
cannam@147 245 dynamicPrintValue(structValue.get(field));
cannam@147 246 }
cannam@147 247 std::cout << ")";
cannam@147 248 break;
cannam@147 249 }
cannam@147 250 default:
cannam@147 251 // There are other types, we aren't handling them.
cannam@147 252 std::cout << "?";
cannam@147 253 break;
cannam@147 254 }
cannam@147 255 }
cannam@147 256
cannam@147 257 void dynamicPrintMessage(int fd, StructSchema schema) {
cannam@147 258 PackedFdMessageReader message(fd);
cannam@147 259 dynamicPrintValue(message.getRoot<DynamicStruct>(schema));
cannam@147 260 std::cout << std::endl;
cannam@147 261 }
cannam@147 262
cannam@147 263 int main(int argc, char* argv[]) {
cannam@147 264 StructSchema schema = Schema::from<AddressBook>();
cannam@147 265 if (argc != 2) {
cannam@147 266 std::cerr << "Missing arg." << std::endl;
cannam@147 267 return 1;
cannam@147 268 } else if (strcmp(argv[1], "write") == 0) {
cannam@147 269 writeAddressBook(1);
cannam@147 270 } else if (strcmp(argv[1], "read") == 0) {
cannam@147 271 printAddressBook(0);
cannam@147 272 } else if (strcmp(argv[1], "dwrite") == 0) {
cannam@147 273 dynamicWriteAddressBook(1, schema);
cannam@147 274 } else if (strcmp(argv[1], "dread") == 0) {
cannam@147 275 dynamicPrintMessage(0, schema);
cannam@147 276 } else {
cannam@147 277 std::cerr << "Invalid arg: " << argv[1] << std::endl;
cannam@147 278 return 1;
cannam@147 279 }
cannam@147 280 return 0;
cannam@147 281 }
cannam@147 282