forked from jmckaskill/go-capnproto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
doc.go
211 lines (158 loc) · 6.54 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
Package capn is a capnproto library for go
see http://kentonv.github.io/capnproto/
capnpc-go provides the compiler backend for capnp
after installing to $PATH capnp files can be compiled with
capnp compile -ogo *.capnp
capnpc-go requires two annotations for all types. This is the package and
import found in go.capnp. Package is needed to know what package to place at
the head of the generated file and what go name to use when referring to the
type from another package. Import should be the fully qualified import path
and is used to generate import statement from other packages and to detect
when two types are in the same package. Typically these are added as file
annotations. For example:
using Go = import "github.com/jmckaskill/go-capnproto/go.capnp";
$Go.package("main");
$Go.import("github.com/jmckaskill/go-capnproto/example");
In capnproto a Message is the logical data unit. It may consist of a number of
segments to allow easier allocation. All objects are values with pointer
semantics that point into the data in a message or segment. Messages can be
read/written from a stream uncompressed or using the capnproto compression.
In this library a *Segment is taken to refer to both a specific segment as
well as the containing message. This is to reduce the number of types generic
code needs to deal with and allows objects to be created in the same segment
as their outer object (thus reducing the number of far pointers).
Most getters/setters in the library don't return an error. Instead a get that
fails due to an invalid pointer, out of bounds, etc will return the default
value. A invalid set will be noop'ed. If you really need to know whether a set
succeeds then errors are provided by the lower level Object methods.
Since go doesn't have any templating, lists are created for the basic types
and one level of named types. The list of basic types (e.g. List(UInt8),
List(Text), etc) are all provided in this library. Lists of user named types
are created with the user types (e.g. user struct Foo will create a Foo_List
type). capnp schemas that use deeper lists (e.g. List(List(UInt8))) will use
PointerList and the user will have to use the Object.ToList* functions to cast
to the correct type.
Structs
capnpc-go will generate the following for structs:
// Foo is a value with pointer semantics referencing the data in a
// segment. Member functions are provided to get/set members in the
// struct. Getters/setters of an outer struct will use values of type
// Foo to set/get pointers.
type Foo capn.Struct
// NewFoo creates a new orphaned Foo struct. This can then be added to
// a message by using a Set function which takes a Foo argument.
func NewFoo(s *capn.Segment) Foo
// NewRootFoo creates a new root of type Foo at the end of the
// provided segment. This is distinct from NewFoo as this always
// creates a root tag. Typically the provided segment should be empty.
func NewRootFoo(s *capn.Segment) Foo
// ReadRootFoo reads the root tag at the beginning of the provided
// segment and returns it as a Foo struct.
func ReadRootFoo(s *capn.Segment) Foo
// Foo_List is a value with pointer semantics. It is created for all
// structs, and is used for List(Foo) in the capnp file.
type Foo_List capn.List
// NewFooList creates a new orphaned List(Foo). This can then be added
// to a message by using a Set function which takes a Foo_List. sz
// specifies the list size. Due to the list using memory directly in
// the outgoing buffer (i.e. arena style memory management), the size
// can not be changed after creation.
func NewFooList(s *capn.Segment, sz int) Foo_List
// Len returns the list length. For composite lists this is the number
// of list elements.
func (s Foo_List) Len() int
// At returns a pointer to the i'th element. If i is an invalid index,
// this will return a null Foo (all getters will return default
// values, setters will fail). For a composite list the returned value
// will be a list member. Setting another value to point to list
// members forces a copy of the data. For pointer lists, the pointer
// value will be auto-derefenced.
func (s Foo_List) At(i int) Foo
// ToArray converts the capnproto list into a go list. For large lists
// this is inefficent as it has to read all elements. This can be
// quite convenient especially for iterating as it lets you use a for
// range clause:
// for i, f := range mylist.ToArray() {}
func (s Foo_List) ToArray() []Foo
Groups
For each group a typedef is created with a different method set for just the
groups fields:
struct Foo {
group :Group {
field @0 :Bool;
}
}
type Foo capn.Struct
type FooGroup Foo
func (s Foo) Group() FooGroup
func (s FooGroup) Field() bool
That way the following may be used to access a field in a group:
var f Foo
value := f.Group().Field()
Note that Group accessors just cast the type and so have no overhead
func (s Foo) Group() FooGroup {return FooGroup(s)}
Unions
Named unions are treated as a group with an inner unnamed union. Unnamed
unions generate an enum Type_which and a corresponding which() function:
struct Foo {
union {
a @0 :Bool;
b @1 :Bool;
}
}
type Foo_which uint16
const (
FOO_A Foo_which = 0
FOO_B = 1
)
func (s Foo) A() bool
func (s Foo) B() bool
func (s Foo) SetA(v bool)
func (s Foo) SetB(v bool)
func (s Foo) which() Foo_which
which() should be checked before using the getters, and the default case must
always be handled.
Setters for single values will set the union discriminator as well as set the
value.
For groups in unions, there is a group setter that just sets the
discriminator. This must be called before the group getter can be used to set
values. For example:
struct Foo {
union {
a :group {
v :Bool
}
b :group {
v :Bool
}
}
}
f.SetA() // Set that we are using group A
f.A().SetV(true) // then we can use the group A getter to set the inner values
Enums
capnpc-go generates enum values in all caps. For example in the capnp file:
enum ElementSize {
empty @0;
bit @1;
byte @2;
twoBytes @3;
fourBytes @4;
eightBytes @5;
pointer @6;
inlineComposite @7;
}
In the generated capnp.go file:
type ElementSize uint16
const (
ELEMENTSIZE_EMPTY ElementSize = 0
ELEMENTSIZE_BIT = 1
ELEMENTSIZE_BYTE = 2
ELEMENTSIZE_TWOBYTES = 3
ELEMENTSIZE_FOURBYTES = 4
ELEMENTSIZE_EIGHTBYTES = 5
ELEMENTSIZE_POINTER = 6
ELEMENTSIZE_INLINECOMPOSITE = 7
)
*/
package capn