Commit 5986724f authored by Kenton Varda's avatar Kenton Varda

Update docs for unions. Also allow setters for void values to omit the parameter.

parent 0df5fb63
......@@ -31,6 +31,7 @@ namespace {
template <typename Builder>
void genericInitTestMessage(Builder builder) {
builder.setVoidField(Void::VOID);
builder.setVoidField(); // Means the same as above.
builder.setBoolField(true);
builder.setInt8Field(-123);
builder.setInt16Field(-12345);
......
......@@ -236,6 +236,9 @@ fieldContext parent desc = mkStrContext context where
context "fieldUnionDiscriminant" = case fieldUnion desc of
Just (_, n) -> MuVariable n
Nothing -> muNull
context "fieldSetterDefault" = case fieldType desc of
BuiltinType BuiltinVoid -> MuVariable " = ::capnproto::Void::VOID"
_ -> MuVariable ""
context s = parent s
unionContext parent desc = mkStrContext context where
......
......@@ -233,7 +233,7 @@ inline {{fieldType}} {{typeFullName}}::Builder::get{{fieldTitleCase}}() {
return _builder.getDataField<{{fieldType}}>(
{{fieldOffset}} * ::capnproto::ELEMENTS{{fieldDefaultMask}});
}
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value) {
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value{{fieldSetterDefault}}) {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
......
......@@ -33,7 +33,7 @@
<ul>
<li><a href="index.html">Introduction</a></li>
<li><a href="install.html">Installation</a></li>
<li><a href="language.html">Defining Types</a></li>
<li><a href="language.html">Schema Language</a></li>
<li><a href="encoding.html">Encoding</a></li>
<li><a href="rpc.html">RPC Protocol</a></li>
<li><a href="cxx.html">C++ Runtime</a></li>
......
......@@ -16,6 +16,26 @@ struct Person {
id @0 :UInt32;
name @1 :Text;
email @2 :Text;
phones @3 :List(PhoneNumber);
struct PhoneNumber {
number @0 :Text;
type @1 :Type;
enum Type {
mobile @0;
home @1;
work @2;
}
}
employment @4 union {
unemployed @5 :Void;
employer @6 :Text;
school @7 :Text;
selfEmployed @8 :Void;
# We assume that a person is only one of these.
}
}
struct AddressBook {
......@@ -29,6 +49,7 @@ You might write code like:
#include "addressbook.capnp.h"
#include <capnproto/message.h>
#include <capnproto/serialize-packed.h>
#include <iostream>
void writeAddressBook(int fd) {
::capnproto::MallocMessageBuilder message;
......@@ -40,11 +61,23 @@ void writeAddressBook(int fd) {
alice.setId(123);
alice.setName("Alice");
alice.setEmail("alice@example.com");
// Type shown for explanation purposes; normally you'd use auto.
capnproto::List<Person::PhoneNumber>::Builder alicePhones =
alice.initPhones(1);
alicePhones[0].setNumber("555-1212");
alicePhones[0].setType(Person::PhoneNumber::Type::MOBILE);
alice.getEmployment().setSchool("MIT");
Person::Builder bob = people[1];
bob.setId(456);
bob.setName("Bob");
bob.setEmail("bob@example.com");
auto bobPhones = bob.initPhones(2);
bobPhones[0].setNumber("555-4567");
bobPhones[0].setType(Person::PhoneNumber::Type::HOME);
bobPhones[1].setNumber("555-7654");
bobPhones[1].setType(Person::PhoneNumber::Type::WORK);
bob.getEmployment().setUnemployed();
writePackedMessageToFd(fd, message);
}
......@@ -56,6 +89,33 @@ void printAddressBook(int fd) {
for (Person::Reader person : addressBook.getPeople()) {
std::cout << person.getName() << ": " << person.getEmail() << std::endl;
for (Person::PhoneNumber::Reader phone: person.getPhones()) {
const char* typeName = "UNKNOWN";
switch (phone.getType()) {
case Person::PhoneNumber::Type::MOBILE: typeName = "mobile"; break;
case Person::PhoneNumber::Type::HOME: typeName = "home"; break;
case Person::PhoneNumber::Type::WORK: typeName = "work"; break;
}
std::cout << " " << typeName << " phone: "
<< phone.getNumber() << std::endl;
}
Person::Employment::Reader employment = person.getEmployment();
switch (employment.which()) {
case Person::Employment::UNEMPLOYED:
std::cout << " unemployed" << std::endl;
break;
case Person::Employment::EMPLOYER:
std::cout << " employer: "
<< employment.getEmployer() << std::endl;
break;
case Person::Employment::SCHOOL:
std::cout << " student at: "
<< employment.getSchool() << std::endl;
break;
case Person::Employment::SELF_EMPLOYED:
std::cout << " self-employed" << std::endl;
break;
}
}
}
{% endhighlight %}
......@@ -183,6 +243,17 @@ void setMyListField(::capnproto::List<double>::Reader value);
::capnproto::List<double>::Builder initMyListField(size_t size);
{% endhighlight %}
## Unions
For each union `foo` declared in the struct, the struct's reader and builder have a method
`getFoo()` which returns a reader/builder for the union. The union reader/builder has accessors
for each field exactly like a struct's accessors. It also has an accessor `which()` which returns
an enum indicating which member of the union is currently set. Setting any member of the union
updates the value returned by `which()`. Getting a member other than the currently-set member
crashes in debug mode or returns garbage when `NDEBUG` is defined.
See the [example](#example_usage) at the top of the page for an example of unions.
## Lists
Lists are represented by the type `capnproto::List<T>`, where `T` is any of the primitive types,
......
......@@ -135,23 +135,24 @@ union declarations do not look like types.
struct Person {
# ...
union employment @4;
unemployed @5 in employment :Void;
employer @6 in employment :Company;
school @7 in employment :School;
selfEmployed @8 in employment :Void;
# We assume that a person is only one of these.
employment @4 union {
unemployed @5 :Void;
employer @6 :Company;
school @7 :School;
selfEmployed @8 :Void;
# We assume that a person is only one of these.
}
}
{% endhighlight %}
Notes:
* Unions are numbered in the same number space as other fields. Remember that the purpose of the
numbers is to indicate the evolution order of the struct. The system needs to know when the union
was declared relative to the fields in it. Also note that no more than one element of the union is
allowed to have a number less than the union's number, as unionizing two or more pre-existing
fields would change their layout.
* Unions and their members are numbered in the same number space as fields of the containing
struct. Remember that the purpose of the numbers is to indicate the evolution order of the
struct. The system needs to know when the union and each of its members was declared relative to
the non-union fields. Also note that no more than one element of the union is allowed to have a
number less than the union's number, as unionizing two or more pre-existing fields would change
their layout.
* Notice that we used the "useless" `Void` type here. We don't have any extra information to store
for the `unemployed` or `selfEmployed` cases, but we still want the union to distinguish these
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment