cloudflared-mirror/vendor/zombiezen.com/go/capnproto2/pogs/doc.go

165 lines
4.8 KiB
Go

/*
Package pogs provides functions to convert Cap'n Proto messages to and
from Go structs. pogs operates similarly to encoding/json: define a
struct that is optionally marked up with tags, then Insert and Extract
will copy the fields to and from the corresponding Cap'n Proto struct.
Inserting
To copy data into a Cap'n Proto struct, we use the Insert function.
Consider the following schema:
struct Message {
name @0 :Text;
body @1 :Text;
time @2 :Int64;
}
and the Go struct:
type Message struct {
Name string
Body string
Time int64
}
We can copy the Go struct into a Cap'n Proto struct like this:
_, arena, _ := capnp.NewMessage(capnp.SingleSegment(nil))
root, _ := myschema.NewRootMessage(arena)
m := &Message{"Alice", "Hello", 1294706395881547000}
err := pogs.Insert(myschema.Message_TypeID, root.Struct, m)
Note that if any field names in our Go struct don't match to a field in
the Cap'n Proto struct, Insert returns an error. We'll see how to fix
that in a moment.
Extracting
Copying data back out from a Cap'n Proto struct is quite similar: we
pass a pointer to our Go struct to Extract.
m := new(Message)
err := pogs.Extract(m, myschema.Message_TypeID, root.Struct)
Types
The mapping between Cap'n Proto types and underlying Go types is as
follows:
Bool -> bool
Int8, Int16, Int32, Int64 -> int8, int16, int32, int64
UInt8, UInt16, UInt32, UInt64 -> uint8, uint16, uint32, uint64
Float32, Float64 -> float32, float64
Text -> either []byte or string
Data -> []byte
List -> slice
enum -> uint16
struct -> a struct or pointer to struct
interface -> a capnp.Client or struct with
exactly one field, named
"Client", of type capnp.Client
Note that the unsized int and uint type can't be used: int and float
types must match in size. For Data and Text fields using []byte, the
filled-in byte slice will point to original segment.
Renaming and Omitting Fields
By default, the Go field name is the same as the Cap'n Proto schema
field name with the first letter capitalized. If we want to change this
mapping, we use the capnp field tag.
type MessageRenamed struct {
Subject string `capnp:"name"`
Body string
SentMillis int64 `capnp:"time"`
}
Using a "-" will cause the field to be ignored by the Insert and
Extract functions.
type ExtraFieldsMessage struct {
ID uint64 `capnp:"-"`
Name string
Body string
Time int64
}
Unions
Since Go does not have support for variant types, Go structs that want
to use fields inside a Cap'n Proto union must have an explicit
discriminant field called Which. The Extract function will populate the
Which field and the Insert function will read the Which field to
determine which field to set. Given this schema:
struct Shape {
area @0 :Float64;
union {
circle @1 :Float64;
square @2 :Float64;
}
}
the Go struct should look like this:
type Shape struct {
Area float64
Which myschema.Shape_Which // or any other uint16 type
Circle float64
Square float64
}
Attempting to use fields in a union without a uint16 Which field will
result in an error. There is one exception: we can declare our Which
field to be fixed to one particular union value by using a field tag.
type Square struct {
Which struct{} `capnp:",which=square"`
Area float64
Width float64 `capnp:"square"`
}
This can be useful if we want to use a different Go type depending on
which field in the union is set.
shape, err := myschema.ReadRootShape(msg)
if err != nil {
return nil, err
}
switch shape.Which() {
case myschema.Shape_Which_square:
sq := new(Square)
err = pogs.Extract(sq, myschema.Square_TypeID, shape.Struct)
return sq, err
case myschema.Shape_Which_circle:
// ...
}
Embedding
Anonymous struct fields are usually extracted or inserted as if their
inner exported fields were fields in the outer struct, subject to the
rules in the next paragraph. An anonymous struct field with a name
given in its capnp tag is treated as having that name, rather than being
anonymous. An anonymous struct field with a capnp tag of "-" will be
ignored.
The visibility rules for struct fields are amended for pogs in the same
way they are amended in encoding/json: if there are multiple fields at
the same level, and that level is the least nested, the following extra
rules apply:
1) Of those fields, if any are capnp-tagged, only tagged fields are
considered, even if there are multiple untagged fields that would
otherwise conflict.
2) If there is exactly one field (tagged or not according to the first
rule), that is selected.
3) Otherwise, there are multiple fields, and all are ignored; no error
occurs.
*/
package pogs // import "zombiezen.com/go/capnproto2/pogs"