comparison src/capnproto-git-20161025/c++/samples/addressbook.c++ @ 133:1ac99bfc383d

Add Cap'n Proto source
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 25 Oct 2016 11:17:01 +0100
parents
children
comparison
equal deleted inserted replaced
132:42a73082be24 133:1ac99bfc383d
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