annotate src/capnproto-git-20161025/c++/samples/addressbook.c++ @ 83:ae30d91d2ffe

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