Mercurial > hg > sv-dependency-builds
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 |