Mercurial > hg > sv-dependency-builds
comparison src/capnproto-0.6.0/c++/samples/addressbook.c++ @ 62:0994c39f1e94
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 |
comparison
equal
deleted
inserted
replaced
| 61:d101c4099725 | 62:0994c39f1e94 |
|---|---|
| 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++11 -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++11 -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 #include "addressbook.capnp.h" | |
| 117 #include <capnp/message.h> | |
| 118 #include <capnp/serialize-packed.h> | |
| 119 #include <iostream> | |
| 120 #include <capnp/schema.h> | |
| 121 #include <capnp/dynamic.h> | |
| 122 | |
| 123 using ::capnp::DynamicValue; | |
| 124 using ::capnp::DynamicStruct; | |
| 125 using ::capnp::DynamicEnum; | |
| 126 using ::capnp::DynamicList; | |
| 127 using ::capnp::List; | |
| 128 using ::capnp::Schema; | |
| 129 using ::capnp::StructSchema; | |
| 130 using ::capnp::EnumSchema; | |
| 131 | |
| 132 using ::capnp::Void; | |
| 133 using ::capnp::Text; | |
| 134 using ::capnp::MallocMessageBuilder; | |
| 135 using ::capnp::PackedFdMessageReader; | |
| 136 | |
| 137 void dynamicWriteAddressBook(int fd, StructSchema schema) { | |
| 138 // Write a message using the dynamic API to set each | |
| 139 // field by text name. This isn't something you'd | |
| 140 // normally want to do; it's just for illustration. | |
| 141 | |
| 142 MallocMessageBuilder message; | |
| 143 | |
| 144 // Types shown for explanation purposes; normally you'd | |
| 145 // use auto. | |
| 146 DynamicStruct::Builder addressBook = | |
| 147 message.initRoot<DynamicStruct>(schema); | |
| 148 | |
| 149 DynamicList::Builder people = | |
| 150 addressBook.init("people", 2).as<DynamicList>(); | |
| 151 | |
| 152 DynamicStruct::Builder alice = | |
| 153 people[0].as<DynamicStruct>(); | |
| 154 alice.set("id", 123); | |
| 155 alice.set("name", "Alice"); | |
| 156 alice.set("email", "alice@example.com"); | |
| 157 auto alicePhones = alice.init("phones", 1).as<DynamicList>(); | |
| 158 auto phone0 = alicePhones[0].as<DynamicStruct>(); | |
| 159 phone0.set("number", "555-1212"); | |
| 160 phone0.set("type", "mobile"); | |
| 161 alice.get("employment").as<DynamicStruct>() | |
| 162 .set("school", "MIT"); | |
| 163 | |
| 164 auto bob = people[1].as<DynamicStruct>(); | |
| 165 bob.set("id", 456); | |
| 166 bob.set("name", "Bob"); | |
| 167 bob.set("email", "bob@example.com"); | |
| 168 | |
| 169 // Some magic: We can convert a dynamic sub-value back to | |
| 170 // the native type with as<T>()! | |
| 171 List<Person::PhoneNumber>::Builder bobPhones = | |
| 172 bob.init("phones", 2).as<List<Person::PhoneNumber>>(); | |
| 173 bobPhones[0].setNumber("555-4567"); | |
| 174 bobPhones[0].setType(Person::PhoneNumber::Type::HOME); | |
| 175 bobPhones[1].setNumber("555-7654"); | |
| 176 bobPhones[1].setType(Person::PhoneNumber::Type::WORK); | |
| 177 bob.get("employment").as<DynamicStruct>() | |
| 178 .set("unemployed", ::capnp::VOID); | |
| 179 | |
| 180 writePackedMessageToFd(fd, message); | |
| 181 } | |
| 182 | |
| 183 void dynamicPrintValue(DynamicValue::Reader value) { | |
| 184 // Print an arbitrary message via the dynamic API by | |
| 185 // iterating over the schema. Look at the handling | |
| 186 // of STRUCT in particular. | |
| 187 | |
| 188 switch (value.getType()) { | |
| 189 case DynamicValue::VOID: | |
| 190 std::cout << ""; | |
| 191 break; | |
| 192 case DynamicValue::BOOL: | |
| 193 std::cout << (value.as<bool>() ? "true" : "false"); | |
| 194 break; | |
| 195 case DynamicValue::INT: | |
| 196 std::cout << value.as<int64_t>(); | |
| 197 break; | |
| 198 case DynamicValue::UINT: | |
| 199 std::cout << value.as<uint64_t>(); | |
| 200 break; | |
| 201 case DynamicValue::FLOAT: | |
| 202 std::cout << value.as<double>(); | |
| 203 break; | |
| 204 case DynamicValue::TEXT: | |
| 205 std::cout << '\"' << value.as<Text>().cStr() << '\"'; | |
| 206 break; | |
| 207 case DynamicValue::LIST: { | |
| 208 std::cout << "["; | |
| 209 bool first = true; | |
| 210 for (auto element: value.as<DynamicList>()) { | |
| 211 if (first) { | |
| 212 first = false; | |
| 213 } else { | |
| 214 std::cout << ", "; | |
| 215 } | |
| 216 dynamicPrintValue(element); | |
| 217 } | |
| 218 std::cout << "]"; | |
| 219 break; | |
| 220 } | |
| 221 case DynamicValue::ENUM: { | |
| 222 auto enumValue = value.as<DynamicEnum>(); | |
| 223 KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) { | |
| 224 std::cout << | |
| 225 enumerant->getProto().getName().cStr(); | |
| 226 } else { | |
| 227 // Unknown enum value; output raw number. | |
| 228 std::cout << enumValue.getRaw(); | |
| 229 } | |
| 230 break; | |
| 231 } | |
| 232 case DynamicValue::STRUCT: { | |
| 233 std::cout << "("; | |
| 234 auto structValue = value.as<DynamicStruct>(); | |
| 235 bool first = true; | |
| 236 for (auto field: structValue.getSchema().getFields()) { | |
| 237 if (!structValue.has(field)) continue; | |
| 238 if (first) { | |
| 239 first = false; | |
| 240 } else { | |
| 241 std::cout << ", "; | |
| 242 } | |
| 243 std::cout << field.getProto().getName().cStr() | |
| 244 << " = "; | |
| 245 dynamicPrintValue(structValue.get(field)); | |
| 246 } | |
| 247 std::cout << ")"; | |
| 248 break; | |
| 249 } | |
| 250 default: | |
| 251 // There are other types, we aren't handling them. | |
| 252 std::cout << "?"; | |
| 253 break; | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 void dynamicPrintMessage(int fd, StructSchema schema) { | |
| 258 PackedFdMessageReader message(fd); | |
| 259 dynamicPrintValue(message.getRoot<DynamicStruct>(schema)); | |
| 260 std::cout << std::endl; | |
| 261 } | |
| 262 | |
| 263 int main(int argc, char* argv[]) { | |
| 264 StructSchema schema = Schema::from<AddressBook>(); | |
| 265 if (argc != 2) { | |
| 266 std::cerr << "Missing arg." << std::endl; | |
| 267 return 1; | |
| 268 } else if (strcmp(argv[1], "write") == 0) { | |
| 269 writeAddressBook(1); | |
| 270 } else if (strcmp(argv[1], "read") == 0) { | |
| 271 printAddressBook(0); | |
| 272 } else if (strcmp(argv[1], "dwrite") == 0) { | |
| 273 dynamicWriteAddressBook(1, schema); | |
| 274 } else if (strcmp(argv[1], "dread") == 0) { | |
| 275 dynamicPrintMessage(0, schema); | |
| 276 } else { | |
| 277 std::cerr << "Invalid arg: " << argv[1] << std::endl; | |
| 278 return 1; | |
| 279 } | |
| 280 return 0; | |
| 281 } | |
| 282 |
