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 { ...@@ -31,6 +31,7 @@ namespace {
template <typename Builder> template <typename Builder>
void genericInitTestMessage(Builder builder) { void genericInitTestMessage(Builder builder) {
builder.setVoidField(Void::VOID); builder.setVoidField(Void::VOID);
builder.setVoidField(); // Means the same as above.
builder.setBoolField(true); builder.setBoolField(true);
builder.setInt8Field(-123); builder.setInt8Field(-123);
builder.setInt16Field(-12345); builder.setInt16Field(-12345);
......
...@@ -236,6 +236,9 @@ fieldContext parent desc = mkStrContext context where ...@@ -236,6 +236,9 @@ fieldContext parent desc = mkStrContext context where
context "fieldUnionDiscriminant" = case fieldUnion desc of context "fieldUnionDiscriminant" = case fieldUnion desc of
Just (_, n) -> MuVariable n Just (_, n) -> MuVariable n
Nothing -> muNull Nothing -> muNull
context "fieldSetterDefault" = case fieldType desc of
BuiltinType BuiltinVoid -> MuVariable " = ::capnproto::Void::VOID"
_ -> MuVariable ""
context s = parent s context s = parent s
unionContext parent desc = mkStrContext context where unionContext parent desc = mkStrContext context where
......
...@@ -233,7 +233,7 @@ inline {{fieldType}} {{typeFullName}}::Builder::get{{fieldTitleCase}}() { ...@@ -233,7 +233,7 @@ inline {{fieldType}} {{typeFullName}}::Builder::get{{fieldTitleCase}}() {
return _builder.getDataField<{{fieldType}}>( return _builder.getDataField<{{fieldType}}>(
{{fieldOffset}} * ::capnproto::ELEMENTS{{fieldDefaultMask}}); {{fieldOffset}} * ::capnproto::ELEMENTS{{fieldDefaultMask}});
} }
inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value) { inline void {{typeFullName}}::Builder::set{{fieldTitleCase}}({{fieldType}} value{{fieldSetterDefault}}) {
{{#fieldUnion}} {{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>( _builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}}); {{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
<ul> <ul>
<li><a href="index.html">Introduction</a></li> <li><a href="index.html">Introduction</a></li>
<li><a href="install.html">Installation</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="encoding.html">Encoding</a></li>
<li><a href="rpc.html">RPC Protocol</a></li> <li><a href="rpc.html">RPC Protocol</a></li>
<li><a href="cxx.html">C++ Runtime</a></li> <li><a href="cxx.html">C++ Runtime</a></li>
......
...@@ -16,6 +16,26 @@ struct Person { ...@@ -16,6 +16,26 @@ struct Person {
id @0 :UInt32; id @0 :UInt32;
name @1 :Text; name @1 :Text;
email @2 :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 { struct AddressBook {
...@@ -29,6 +49,7 @@ You might write code like: ...@@ -29,6 +49,7 @@ You might write code like:
#include "addressbook.capnp.h" #include "addressbook.capnp.h"
#include <capnproto/message.h> #include <capnproto/message.h>
#include <capnproto/serialize-packed.h> #include <capnproto/serialize-packed.h>
#include <iostream>
void writeAddressBook(int fd) { void writeAddressBook(int fd) {
::capnproto::MallocMessageBuilder message; ::capnproto::MallocMessageBuilder message;
...@@ -40,11 +61,23 @@ void writeAddressBook(int fd) { ...@@ -40,11 +61,23 @@ void writeAddressBook(int fd) {
alice.setId(123); alice.setId(123);
alice.setName("Alice"); alice.setName("Alice");
alice.setEmail("alice@example.com"); 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]; Person::Builder bob = people[1];
bob.setId(456); bob.setId(456);
bob.setName("Bob"); bob.setName("Bob");
bob.setEmail("bob@example.com"); 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); writePackedMessageToFd(fd, message);
} }
...@@ -56,6 +89,33 @@ void printAddressBook(int fd) { ...@@ -56,6 +89,33 @@ void printAddressBook(int fd) {
for (Person::Reader person : addressBook.getPeople()) { for (Person::Reader person : addressBook.getPeople()) {
std::cout << person.getName() << ": " << person.getEmail() << std::endl; 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 %} {% endhighlight %}
...@@ -183,6 +243,17 @@ void setMyListField(::capnproto::List<double>::Reader value); ...@@ -183,6 +243,17 @@ void setMyListField(::capnproto::List<double>::Reader value);
::capnproto::List<double>::Builder initMyListField(size_t size); ::capnproto::List<double>::Builder initMyListField(size_t size);
{% endhighlight %} {% 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
Lists are represented by the type `capnproto::List<T>`, where `T` is any of the primitive types, 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. ...@@ -135,23 +135,24 @@ union declarations do not look like types.
struct Person { struct Person {
# ... # ...
union employment @4; employment @4 union {
unemployed @5 :Void;
unemployed @5 in employment :Void; employer @6 :Company;
employer @6 in employment :Company; school @7 :School;
school @7 in employment :School; selfEmployed @8 :Void;
selfEmployed @8 in employment :Void; # We assume that a person is only one of these.
# We assume that a person is only one of these. }
} }
{% endhighlight %} {% endhighlight %}
Notes: Notes:
* Unions are numbered in the same number space as other fields. Remember that the purpose of the * Unions and their members are numbered in the same number space as fields of the containing
numbers is to indicate the evolution order of the struct. The system needs to know when the union struct. Remember that the purpose of the numbers is to indicate the evolution order of the
was declared relative to the fields in it. Also note that no more than one element of the union is struct. The system needs to know when the union and each of its members was declared relative to
allowed to have a number less than the union's number, as unionizing two or more pre-existing the non-union fields. Also note that no more than one element of the union is allowed to have a
fields would change their layout. 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 * 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 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