mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 23:49:57 +00:00
TUN-528: Move cloudflared into a separate repo
This commit is contained in:
37
vendor/zombiezen.com/go/capnproto2/pogs/BUILD.bazel
generated
vendored
Normal file
37
vendor/zombiezen.com/go/capnproto2/pogs/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"extract.go",
|
||||
"fields.go",
|
||||
"insert.go",
|
||||
],
|
||||
importpath = "zombiezen.com/go/capnproto2/pogs",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//:go_default_library",
|
||||
"//internal/nodemap:go_default_library",
|
||||
"//internal/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"bench_test.go",
|
||||
"embed_test.go",
|
||||
"example_test.go",
|
||||
"interface_test.go",
|
||||
"pogs_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//:go_default_library",
|
||||
"//internal/aircraftlib:go_default_library",
|
||||
"//internal/demo/books:go_default_library",
|
||||
"@com_github_kylelemons_godebug//pretty:go_default_library",
|
||||
"@org_golang_x_net//context:go_default_library",
|
||||
],
|
||||
)
|
77
vendor/zombiezen.com/go/capnproto2/pogs/bench_test.go
generated
vendored
Normal file
77
vendor/zombiezen.com/go/capnproto2/pogs/bench_test.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
air "zombiezen.com/go/capnproto2/internal/aircraftlib"
|
||||
)
|
||||
|
||||
type A struct {
|
||||
Name string
|
||||
BirthDay int64
|
||||
Phone string
|
||||
Siblings int32
|
||||
Spouse bool
|
||||
Money float64
|
||||
}
|
||||
|
||||
func generateA(r *rand.Rand) *A {
|
||||
return &A{
|
||||
Name: randString(r, 16),
|
||||
BirthDay: r.Int63(),
|
||||
Phone: randString(r, 10),
|
||||
Siblings: r.Int31n(5),
|
||||
Spouse: r.Intn(2) == 1,
|
||||
Money: r.Float64(),
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExtract(b *testing.B) {
|
||||
r := rand.New(rand.NewSource(12345))
|
||||
data := make([][]byte, 1000)
|
||||
for i := range data {
|
||||
a := generateA(r)
|
||||
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
root, _ := air.NewRootBenchmarkA(seg)
|
||||
Insert(air.BenchmarkA_TypeID, root.Struct, a)
|
||||
data[i], _ = msg.Marshal()
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
msg, _ := capnp.Unmarshal(data[r.Intn(len(data))])
|
||||
root, _ := msg.RootPtr()
|
||||
var a A
|
||||
Extract(&a, air.BenchmarkA_TypeID, root.Struct())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInsert(b *testing.B) {
|
||||
r := rand.New(rand.NewSource(12345))
|
||||
data := make([]*A, 1000)
|
||||
for i := range data {
|
||||
data[i] = generateA(r)
|
||||
}
|
||||
arena := make([]byte, 0, 512)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
a := data[r.Intn(len(data))]
|
||||
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(arena[:0]))
|
||||
root, _ := air.NewRootBenchmarkA(seg)
|
||||
Insert(air.BenchmarkA_TypeID, root.Struct, a)
|
||||
msg.Marshal()
|
||||
}
|
||||
}
|
||||
|
||||
func randString(r *rand.Rand, n int) string {
|
||||
b := make([]byte, (n+1)/2)
|
||||
// Go 1.6 adds a Rand.Read method, but since we want to be compatible with Go 1.4...
|
||||
for i := range b {
|
||||
b[i] = byte(r.Intn(255))
|
||||
}
|
||||
return hex.EncodeToString(b)[:n]
|
||||
}
|
164
vendor/zombiezen.com/go/capnproto2/pogs/doc.go
generated
vendored
Normal file
164
vendor/zombiezen.com/go/capnproto2/pogs/doc.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
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"
|
360
vendor/zombiezen.com/go/capnproto2/pogs/embed_test.go
generated
vendored
Normal file
360
vendor/zombiezen.com/go/capnproto2/pogs/embed_test.go
generated
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
air "zombiezen.com/go/capnproto2/internal/aircraftlib"
|
||||
)
|
||||
|
||||
type VerVal struct {
|
||||
Val int16
|
||||
}
|
||||
|
||||
type VerOneData struct {
|
||||
VerVal
|
||||
}
|
||||
|
||||
type VerTwoData struct {
|
||||
*VerVal
|
||||
Duo int64
|
||||
}
|
||||
|
||||
type F16 struct {
|
||||
PlaneBase `capnp:"base"`
|
||||
}
|
||||
|
||||
func TestExtract_Embed(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v1, err := air.NewRootVerOneData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerOneData: %v", err)
|
||||
}
|
||||
v1.SetVal(123)
|
||||
out := new(VerOneData)
|
||||
if err := Extract(out, air.VerOneData_TypeID, v1.Struct); err != nil {
|
||||
t.Errorf("Extract error: %v", err)
|
||||
}
|
||||
if out.Val != 123 {
|
||||
t.Errorf("Extract produced %s; want %s", zpretty.Sprint(out), zpretty.Sprint(&VerOneData{VerVal{123}}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtract_EmbedPtr(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v2, err := air.NewRootVerTwoData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerTwoData: %v", err)
|
||||
}
|
||||
v2.SetVal(123)
|
||||
v2.SetDuo(456)
|
||||
out := new(VerTwoData)
|
||||
if err := Extract(out, air.VerTwoData_TypeID, v2.Struct); err != nil {
|
||||
t.Errorf("Extract error: %v", err)
|
||||
}
|
||||
if out.VerVal == nil || out.Val != 123 || out.Duo != 456 {
|
||||
t.Errorf("Extract produced %s; want %s", zpretty.Sprint(out), zpretty.Sprint(&VerTwoData{&VerVal{123}, 456}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtract_EmbedOmit(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v2, err := air.NewRootVerTwoData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerTwoData: %v", err)
|
||||
}
|
||||
v2.SetVal(123)
|
||||
v2.SetDuo(456)
|
||||
out := new(VerTwoDataOmit)
|
||||
if err := Extract(out, air.VerTwoData_TypeID, v2.Struct); err != nil {
|
||||
t.Errorf("Extract error: %v", err)
|
||||
}
|
||||
if out.Val != 0 || out.Duo != 456 {
|
||||
t.Errorf("Extract produced %s; want %s", zpretty.Sprint(out), zpretty.Sprint(&VerTwoDataOmit{VerVal{}, 456}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtract_EmbedName(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
f16, err := air.NewRootF16(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootF16: %v", err)
|
||||
}
|
||||
base, err := f16.NewBase()
|
||||
if err != nil {
|
||||
t.Fatalf("F16.NewBase: %v", err)
|
||||
}
|
||||
if err := base.SetName("ALL YOUR BASE"); err != nil {
|
||||
t.Fatalf("Planebase.SetName: %v", err)
|
||||
}
|
||||
base.SetRating(5)
|
||||
base.SetCanFly(true)
|
||||
|
||||
out := new(F16)
|
||||
if err := Extract(out, air.F16_TypeID, f16.Struct); err != nil {
|
||||
t.Errorf("Extract error: %v", err)
|
||||
}
|
||||
if out.Name != "ALL YOUR BASE" || out.Rating != 5 || !out.CanFly {
|
||||
t.Errorf("Extract produced %s; want %s", zpretty.Sprint(out), zpretty.Sprint(&F16{PlaneBase{Name: "ALL YOUR BASE", Rating: 5, CanFly: true}}))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_Embed(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v1, err := air.NewRootVerOneData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerOneData: %v", err)
|
||||
}
|
||||
gv1 := &VerOneData{VerVal{123}}
|
||||
err = Insert(air.VerOneData_TypeID, v1.Struct, gv1)
|
||||
if err != nil {
|
||||
t.Errorf("Insert(%s) error: %v", zpretty.Sprint(gv1), err)
|
||||
}
|
||||
if v1.Val() != 123 {
|
||||
t.Errorf("Insert(%s) produced %v", zpretty.Sprint(gv1), v1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_EmbedPtr(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v2, err := air.NewRootVerTwoData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerTwoData: %v", err)
|
||||
}
|
||||
gv2 := &VerTwoData{&VerVal{123}, 456}
|
||||
err = Insert(air.VerTwoData_TypeID, v2.Struct, gv2)
|
||||
if err != nil {
|
||||
t.Errorf("Insert(%s) error: %v", zpretty.Sprint(gv2), err)
|
||||
}
|
||||
if v2.Val() != 123 || v2.Duo() != 456 {
|
||||
t.Errorf("Insert(%s) produced %v", zpretty.Sprint(gv2), v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_EmbedNilPtr(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v2, err := air.NewRootVerTwoData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerTwoData: %v", err)
|
||||
}
|
||||
gv2 := &VerTwoData{nil, 456}
|
||||
err = Insert(air.VerTwoData_TypeID, v2.Struct, gv2)
|
||||
if err != nil {
|
||||
t.Errorf("Insert(%s) error: %v", zpretty.Sprint(gv2), err)
|
||||
}
|
||||
if v2.Val() != 0 || v2.Duo() != 456 {
|
||||
t.Errorf("Insert(%s) produced %v", zpretty.Sprint(gv2), v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_EmbedOmit(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v2, err := air.NewRootVerTwoData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerTwoData: %v", err)
|
||||
}
|
||||
in := &VerTwoDataOmit{VerVal{123}, 456}
|
||||
err = Insert(air.VerTwoData_TypeID, v2.Struct, in)
|
||||
if err != nil {
|
||||
t.Errorf("Insert(%s) error: %v", zpretty.Sprint(in), err)
|
||||
}
|
||||
if v2.Val() != 0 || v2.Duo() != 456 {
|
||||
t.Errorf("Insert(%s) produced %v", zpretty.Sprint(in), v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_EmbedNamed(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
f16, err := air.NewRootF16(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootF16: %v", err)
|
||||
}
|
||||
in := &F16{PlaneBase{Name: "ALL YOUR BASE", Rating: 5, CanFly: true}}
|
||||
err = Insert(air.F16_TypeID, f16.Struct, in)
|
||||
if err != nil {
|
||||
t.Errorf("Insert(%s) error: %v", zpretty.Sprint(in), err)
|
||||
}
|
||||
base, err := f16.Base()
|
||||
if err != nil {
|
||||
t.Errorf("f16.base: %v", err)
|
||||
}
|
||||
name, err := base.Name()
|
||||
if err != nil {
|
||||
t.Errorf("f16.base.name: %v", err)
|
||||
}
|
||||
if name != "ALL YOUR BASE" || base.Rating() != 5 || !base.CanFly() {
|
||||
t.Errorf("Insert(%s) produced %v", zpretty.Sprint(in), f16)
|
||||
}
|
||||
}
|
||||
|
||||
type VerValNoTag struct {
|
||||
Val int16
|
||||
}
|
||||
|
||||
type VerValTag1 struct {
|
||||
Val int16 `capnp:"val"`
|
||||
}
|
||||
|
||||
type VerValTag2 struct {
|
||||
Val int16 `capnp:"val"`
|
||||
}
|
||||
|
||||
type VerValTag3 struct {
|
||||
Val int16 `capnp:"val"`
|
||||
}
|
||||
|
||||
type VerTwoDataOmit struct {
|
||||
VerVal `capnp:"-"`
|
||||
Duo int64
|
||||
}
|
||||
|
||||
type VerOneDataTop struct {
|
||||
Val int16
|
||||
VerVal
|
||||
}
|
||||
|
||||
type VerOneDataTopWithLowerCollision struct {
|
||||
Val int16
|
||||
VerVal
|
||||
VerValNoTag
|
||||
}
|
||||
|
||||
type VerOneDataNoTags struct {
|
||||
VerVal
|
||||
VerValNoTag
|
||||
}
|
||||
|
||||
type VerOneData1Tag struct {
|
||||
VerVal
|
||||
VerValTag1
|
||||
}
|
||||
|
||||
type VerOneData1TagWithUntagged struct {
|
||||
VerVal
|
||||
VerValTag1
|
||||
VerValNoTag
|
||||
}
|
||||
|
||||
type VerOneData2Tags struct {
|
||||
VerValTag1
|
||||
VerValTag2
|
||||
}
|
||||
|
||||
type VerOneData3Tags struct {
|
||||
VerValTag1
|
||||
VerValTag2
|
||||
VerValTag3
|
||||
}
|
||||
|
||||
func TestExtract_EmbedCollide(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("NewMessage: %v", err)
|
||||
}
|
||||
v1, err := air.NewRootVerOneData(seg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRootVerOneData: %v", err)
|
||||
}
|
||||
v1.SetVal(123)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
want interface{}
|
||||
}{
|
||||
{"top", &VerOneDataTop{Val: 123}},
|
||||
{"no tags", &VerOneDataNoTags{}},
|
||||
{"1 tag", &VerOneData1Tag{VerValTag1: VerValTag1{123}}},
|
||||
{"1 tag with untagged", &VerOneData1TagWithUntagged{VerValTag1: VerValTag1{123}}},
|
||||
{"2 tags", &VerOneData2Tags{}},
|
||||
{"3 tags", &VerOneData3Tags{}},
|
||||
{"top with lower collision", &VerOneDataTopWithLowerCollision{Val: 123}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
out := reflect.New(reflect.TypeOf(test.want).Elem()).Interface()
|
||||
if err := Extract(out, air.VerOneData_TypeID, v1.Struct); err != nil {
|
||||
t.Errorf("%s: Extract error: %v", test.name, err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, test.want) {
|
||||
t.Errorf("%s: Extract produced %s; want %s", test.name, zpretty.Sprint(out), zpretty.Sprint(test.want))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert_EmbedCollide(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in interface{}
|
||||
val int16
|
||||
}{
|
||||
{"top", &VerOneDataTop{Val: 123, VerVal: VerVal{456}}, 123},
|
||||
{"no tags", &VerOneDataNoTags{VerVal: VerVal{123}, VerValNoTag: VerValNoTag{456}}, 0},
|
||||
{"1 tag", &VerOneData1Tag{VerVal: VerVal{123}, VerValTag1: VerValTag1{456}}, 456},
|
||||
{
|
||||
"1 tag with untagged",
|
||||
&VerOneData1TagWithUntagged{
|
||||
VerVal: VerVal{123},
|
||||
VerValTag1: VerValTag1{456},
|
||||
VerValNoTag: VerValNoTag{789},
|
||||
},
|
||||
456,
|
||||
},
|
||||
{"2 tags", &VerOneData2Tags{VerValTag1: VerValTag1{123}, VerValTag2: VerValTag2{456}}, 0},
|
||||
{"3 tags", &VerOneData3Tags{VerValTag1: VerValTag1{123}, VerValTag2: VerValTag2{456}, VerValTag3: VerValTag3{789}}, 0},
|
||||
{
|
||||
"top with lower collision",
|
||||
&VerOneDataTopWithLowerCollision{
|
||||
Val: 123,
|
||||
VerVal: VerVal{456},
|
||||
VerValNoTag: VerValNoTag{789},
|
||||
},
|
||||
123,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewMessage: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
v1, err := air.NewRootVerOneData(seg)
|
||||
if err != nil {
|
||||
t.Errorf("%s: NewRootVerOneData: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
err = Insert(air.VerOneData_TypeID, v1.Struct, test.in)
|
||||
if err != nil {
|
||||
t.Errorf("%s: Insert(..., %s): %v", test.name, zpretty.Sprint(test.in), err)
|
||||
}
|
||||
if v1.Val() != test.val {
|
||||
t.Errorf("%s: Insert(..., %s) produced %v; want (val = %d)", test.name, zpretty.Sprint(test.in), v1, test.val)
|
||||
}
|
||||
}
|
||||
}
|
87
vendor/zombiezen.com/go/capnproto2/pogs/example_test.go
generated
vendored
Normal file
87
vendor/zombiezen.com/go/capnproto2/pogs/example_test.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package pogs_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/internal/demo/books"
|
||||
"zombiezen.com/go/capnproto2/pogs"
|
||||
)
|
||||
|
||||
var bookData = []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0xa0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
|
||||
0x57, 0x61, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20,
|
||||
0x50, 0x65, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func ExampleExtract() {
|
||||
// books.capnp:
|
||||
// struct Book {
|
||||
// title @0 :Text;
|
||||
// pageCount @1 :Int32;
|
||||
// }
|
||||
|
||||
type Book struct {
|
||||
Title string
|
||||
PageCount int32
|
||||
}
|
||||
|
||||
// Read the message from bytes.
|
||||
msg, err := capnp.Unmarshal(bookData)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
root, err := msg.RootPtr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Extract the book from the root struct.
|
||||
b := new(Book)
|
||||
if err := pogs.Extract(b, books.Book_TypeID, root.Struct()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%q has %d pages\n", b.Title, b.PageCount)
|
||||
|
||||
// Output:
|
||||
// "War and Peace" has 1440 pages
|
||||
}
|
||||
|
||||
func ExampleInsert() {
|
||||
// books.capnp:
|
||||
// struct Book {
|
||||
// title @0 :Text;
|
||||
// pageCount @1 :Int32;
|
||||
// }
|
||||
|
||||
type Book struct {
|
||||
Title string
|
||||
PageCount int32
|
||||
}
|
||||
|
||||
// Allocate a new Cap'n Proto Book struct.
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
root, err := books.NewRootBook(seg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Insert the book struct into the Cap'n Proto struct.
|
||||
b := &Book{
|
||||
Title: "War and Peace",
|
||||
PageCount: 1440,
|
||||
}
|
||||
if err := pogs.Insert(books.Book_TypeID, root.Struct, b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(root)
|
||||
|
||||
// Output:
|
||||
// (title = "War and Peace", pageCount = 1440)
|
||||
}
|
418
vendor/zombiezen.com/go/capnproto2/pogs/extract.go
generated
vendored
Normal file
418
vendor/zombiezen.com/go/capnproto2/pogs/extract.go
generated
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/internal/nodemap"
|
||||
"zombiezen.com/go/capnproto2/internal/schema"
|
||||
)
|
||||
|
||||
// Extract copies s into val, a pointer to a Go struct.
|
||||
func Extract(val interface{}, typeID uint64, s capnp.Struct) error {
|
||||
e := new(extracter)
|
||||
err := e.extractStruct(reflect.ValueOf(val), typeID, s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pogs: extract @%#x: %v", typeID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type extracter struct {
|
||||
nodes nodemap.Map
|
||||
}
|
||||
|
||||
var clientType = reflect.TypeOf((*capnp.Client)(nil)).Elem()
|
||||
|
||||
func (e *extracter) extractStruct(val reflect.Value, typeID uint64, s capnp.Struct) error {
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.Type().Elem().Kind() != reflect.Struct {
|
||||
return fmt.Errorf("can't extract struct into %v", val.Type())
|
||||
}
|
||||
switch {
|
||||
case !val.CanSet() && val.IsNil():
|
||||
// Even if the Cap'n Proto pointer isn't valid, this is probably
|
||||
// the caller's fault and will be a bug at some point.
|
||||
return errors.New("can't extract struct into nil")
|
||||
case !s.IsValid() && val.CanSet():
|
||||
val.Set(reflect.Zero(val.Type()))
|
||||
return nil
|
||||
case s.IsValid() && val.CanSet() && val.IsNil():
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
} else if val.Kind() != reflect.Struct {
|
||||
return fmt.Errorf("can't extract struct into %v", val.Type())
|
||||
}
|
||||
if !val.CanSet() {
|
||||
return errors.New("can't modify struct, did you pass in a pointer to your struct?")
|
||||
}
|
||||
n, err := e.nodes.Find(typeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !n.IsValid() || n.Which() != schema.Node_Which_structNode {
|
||||
return fmt.Errorf("cannot find struct type %#x", typeID)
|
||||
}
|
||||
props, err := mapStruct(val.Type(), n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't extract %s: %v", val.Type(), err)
|
||||
}
|
||||
var discriminant uint16
|
||||
hasWhich := false
|
||||
if hasDiscriminant(n) {
|
||||
discriminant = s.Uint16(capnp.DataOffset(n.StructNode().DiscriminantOffset() * 2))
|
||||
if err := props.setWhich(val, discriminant); err == nil {
|
||||
hasWhich = true
|
||||
} else if !isNoWhichError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fields, err := n.StructNode().Fields()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
f := fields.At(i)
|
||||
vf := props.makeFieldByOrdinal(val, i)
|
||||
if !vf.IsValid() {
|
||||
// Don't have a field for this.
|
||||
continue
|
||||
}
|
||||
if dv := f.DiscriminantValue(); dv != schema.Field_noDiscriminant {
|
||||
if !hasWhich {
|
||||
return fmt.Errorf("can't extract %s into %v: has union field but no Which field", shortDisplayName(n), val.Type())
|
||||
}
|
||||
if dv != discriminant {
|
||||
continue
|
||||
}
|
||||
}
|
||||
switch f.Which() {
|
||||
case schema.Field_Which_slot:
|
||||
if err := e.extractField(vf, s, f); err != nil {
|
||||
return err
|
||||
}
|
||||
case schema.Field_Which_group:
|
||||
if err := e.extractStruct(vf, f.Group().TypeId(), s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extracter) extractField(val reflect.Value, s capnp.Struct, f schema.Field) error {
|
||||
typ, err := f.Slot().Type()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dv, err := f.Slot().DefaultValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dv.IsValid() && int(typ.Which()) != int(dv.Which()) {
|
||||
name, _ := f.NameBytes()
|
||||
return fmt.Errorf("extract field %s: default value is a %v, want %v", name, dv.Which(), typ.Which())
|
||||
}
|
||||
if !isTypeMatch(val.Type(), typ) {
|
||||
name, _ := f.NameBytes()
|
||||
return fmt.Errorf("can't extract field %s of type %v into a Go %v", name, typ.Which(), val.Type())
|
||||
}
|
||||
switch typ.Which() {
|
||||
case schema.Type_Which_bool:
|
||||
v := s.Bit(capnp.BitOffset(f.Slot().Offset()))
|
||||
d := dv.Bool()
|
||||
val.SetBool(v != d) // != acts as XOR
|
||||
case schema.Type_Which_int8:
|
||||
v := int8(s.Uint8(capnp.DataOffset(f.Slot().Offset())))
|
||||
d := dv.Int8()
|
||||
val.SetInt(int64(v ^ d))
|
||||
case schema.Type_Which_int16:
|
||||
v := int16(s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)))
|
||||
d := dv.Int16()
|
||||
val.SetInt(int64(v ^ d))
|
||||
case schema.Type_Which_int32:
|
||||
v := int32(s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)))
|
||||
d := dv.Int32()
|
||||
val.SetInt(int64(v ^ d))
|
||||
case schema.Type_Which_int64:
|
||||
v := int64(s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)))
|
||||
d := dv.Int64()
|
||||
val.SetInt(v ^ d)
|
||||
case schema.Type_Which_uint8:
|
||||
v := s.Uint8(capnp.DataOffset(f.Slot().Offset()))
|
||||
d := dv.Uint8()
|
||||
val.SetUint(uint64(v ^ d))
|
||||
case schema.Type_Which_uint16:
|
||||
v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2))
|
||||
d := dv.Uint16()
|
||||
val.SetUint(uint64(v ^ d))
|
||||
case schema.Type_Which_enum:
|
||||
v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2))
|
||||
d := dv.Enum()
|
||||
val.SetUint(uint64(v ^ d))
|
||||
case schema.Type_Which_uint32:
|
||||
v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4))
|
||||
d := dv.Uint32()
|
||||
val.SetUint(uint64(v ^ d))
|
||||
case schema.Type_Which_uint64:
|
||||
v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8))
|
||||
d := dv.Uint64()
|
||||
val.SetUint(v ^ d)
|
||||
case schema.Type_Which_float32:
|
||||
v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4))
|
||||
d := math.Float32bits(dv.Float32())
|
||||
val.SetFloat(float64(math.Float32frombits(v ^ d)))
|
||||
case schema.Type_Which_float64:
|
||||
v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8))
|
||||
d := math.Float64bits(dv.Float64())
|
||||
val.SetFloat(math.Float64frombits(v ^ d))
|
||||
case schema.Type_Which_text:
|
||||
p, err := s.Ptr(uint16(f.Slot().Offset()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var b []byte
|
||||
if p.IsValid() {
|
||||
b = p.TextBytes()
|
||||
} else {
|
||||
b, _ = dv.TextBytes()
|
||||
}
|
||||
if val.Kind() == reflect.String {
|
||||
val.SetString(string(b))
|
||||
} else {
|
||||
// byte slice, as guaranteed by isTypeMatch
|
||||
val.SetBytes(b)
|
||||
}
|
||||
case schema.Type_Which_data:
|
||||
p, err := s.Ptr(uint16(f.Slot().Offset()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var b []byte
|
||||
if p.IsValid() {
|
||||
b = p.Data()
|
||||
} else {
|
||||
b, _ = dv.Data()
|
||||
}
|
||||
val.SetBytes(b)
|
||||
case schema.Type_Which_structType:
|
||||
p, err := s.Ptr(uint16(f.Slot().Offset()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss := p.Struct()
|
||||
if !ss.IsValid() {
|
||||
p, _ = dv.StructValuePtr()
|
||||
ss = p.Struct()
|
||||
}
|
||||
return e.extractStruct(val, typ.StructType().TypeId(), ss)
|
||||
case schema.Type_Which_list:
|
||||
p, err := s.Ptr(uint16(f.Slot().Offset()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l := p.List()
|
||||
if !l.IsValid() {
|
||||
p, _ = dv.ListPtr()
|
||||
l = p.List()
|
||||
}
|
||||
return e.extractList(val, typ, l)
|
||||
case schema.Type_Which_interface:
|
||||
p, err := s.Ptr(uint16(f.Slot().Offset()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if val.Type() != clientType {
|
||||
// Must be a struct wrapper.
|
||||
val = val.FieldByName("Client")
|
||||
}
|
||||
|
||||
client := p.Interface().Client()
|
||||
if client == nil {
|
||||
val.Set(reflect.Zero(val.Type()))
|
||||
} else {
|
||||
val.Set(reflect.ValueOf(client))
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown field type %v", typ.Which())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *extracter) extractList(val reflect.Value, typ schema.Type, l capnp.List) error {
|
||||
vt := val.Type()
|
||||
elem, err := typ.List().ElementType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isTypeMatch(vt, typ) {
|
||||
// TODO(light): the error won't be that useful for nested lists.
|
||||
return fmt.Errorf("can't extract %v list into a Go %v", elem.Which(), vt)
|
||||
}
|
||||
if !l.IsValid() {
|
||||
val.Set(reflect.Zero(vt))
|
||||
return nil
|
||||
}
|
||||
n := l.Len()
|
||||
val.Set(reflect.MakeSlice(vt, n, n))
|
||||
switch elem.Which() {
|
||||
case schema.Type_Which_bool:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetBool(capnp.BitList{List: l}.At(i))
|
||||
}
|
||||
case schema.Type_Which_int8:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetInt(int64(capnp.Int8List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_int16:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetInt(int64(capnp.Int16List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_int32:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetInt(int64(capnp.Int32List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_int64:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetInt(capnp.Int64List{List: l}.At(i))
|
||||
}
|
||||
case schema.Type_Which_uint8:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetUint(uint64(capnp.UInt8List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_uint16, schema.Type_Which_enum:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetUint(uint64(capnp.UInt16List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_uint32:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetUint(uint64(capnp.UInt32List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_uint64:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetUint(capnp.UInt64List{List: l}.At(i))
|
||||
}
|
||||
case schema.Type_Which_float32:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetFloat(float64(capnp.Float32List{List: l}.At(i)))
|
||||
}
|
||||
case schema.Type_Which_float64:
|
||||
for i := 0; i < n; i++ {
|
||||
val.Index(i).SetFloat(capnp.Float64List{List: l}.At(i))
|
||||
}
|
||||
case schema.Type_Which_text:
|
||||
if val.Type().Elem().Kind() == reflect.String {
|
||||
for i := 0; i < n; i++ {
|
||||
s, err := capnp.TextList{List: l}.At(i)
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
val.Index(i).SetString(s)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < n; i++ {
|
||||
b, err := capnp.TextList{List: l}.BytesAt(i)
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
val.Index(i).SetBytes(b)
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_data:
|
||||
for i := 0; i < n; i++ {
|
||||
b, err := capnp.DataList{List: l}.At(i)
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
val.Index(i).SetBytes(b)
|
||||
}
|
||||
case schema.Type_Which_list:
|
||||
for i := 0; i < n; i++ {
|
||||
p, err := capnp.PointerList{List: l}.PtrAt(i)
|
||||
// TODO(light): collect errors and finish
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.extractList(val.Index(i), elem, p.List()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_structType:
|
||||
if val.Type().Elem().Kind() == reflect.Struct {
|
||||
for i := 0; i < n; i++ {
|
||||
err := e.extractStruct(val.Index(i), elem.StructType().TypeId(), l.Struct(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < n; i++ {
|
||||
newval := reflect.New(val.Type().Elem().Elem())
|
||||
val.Index(i).Set(newval)
|
||||
err := e.extractStruct(newval, elem.StructType().TypeId(), l.Struct(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown list type %v", elem.Which())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var typeMap = map[schema.Type_Which]reflect.Kind{
|
||||
schema.Type_Which_bool: reflect.Bool,
|
||||
schema.Type_Which_int8: reflect.Int8,
|
||||
schema.Type_Which_int16: reflect.Int16,
|
||||
schema.Type_Which_int32: reflect.Int32,
|
||||
schema.Type_Which_int64: reflect.Int64,
|
||||
schema.Type_Which_uint8: reflect.Uint8,
|
||||
schema.Type_Which_uint16: reflect.Uint16,
|
||||
schema.Type_Which_uint32: reflect.Uint32,
|
||||
schema.Type_Which_uint64: reflect.Uint64,
|
||||
schema.Type_Which_float32: reflect.Float32,
|
||||
schema.Type_Which_float64: reflect.Float64,
|
||||
schema.Type_Which_enum: reflect.Uint16,
|
||||
}
|
||||
|
||||
func isTypeMatch(r reflect.Type, s schema.Type) bool {
|
||||
switch s.Which() {
|
||||
case schema.Type_Which_text:
|
||||
return r.Kind() == reflect.String || r.Kind() == reflect.Slice && r.Elem().Kind() == reflect.Uint8
|
||||
case schema.Type_Which_data:
|
||||
return r.Kind() == reflect.Slice && r.Elem().Kind() == reflect.Uint8
|
||||
case schema.Type_Which_structType:
|
||||
return isStructOrStructPtr(r)
|
||||
case schema.Type_Which_list:
|
||||
e, _ := s.List().ElementType()
|
||||
return r.Kind() == reflect.Slice && isTypeMatch(r.Elem(), e)
|
||||
case schema.Type_Which_interface:
|
||||
if r == clientType {
|
||||
return true
|
||||
}
|
||||
|
||||
// Otherwise, the type must be a struct with one element named
|
||||
// "Client" of type capnp.Client.
|
||||
if r.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
if r.NumField() != 1 {
|
||||
return false
|
||||
}
|
||||
field, ok := r.FieldByName("Client")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return field.Type == clientType
|
||||
}
|
||||
k, ok := typeMap[s.Which()]
|
||||
return ok && k == r.Kind()
|
||||
}
|
350
vendor/zombiezen.com/go/capnproto2/pogs/fields.go
generated
vendored
Normal file
350
vendor/zombiezen.com/go/capnproto2/pogs/fields.go
generated
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"zombiezen.com/go/capnproto2/internal/schema"
|
||||
)
|
||||
|
||||
type fieldProps struct {
|
||||
schemaName string // empty if doesn't map to schema
|
||||
typ fieldType
|
||||
fixedWhich string
|
||||
tagged bool
|
||||
}
|
||||
|
||||
type fieldType int
|
||||
|
||||
const (
|
||||
mappedField fieldType = iota
|
||||
whichField
|
||||
embedField
|
||||
)
|
||||
|
||||
func parseField(f reflect.StructField, hasDiscrim bool) fieldProps {
|
||||
var p fieldProps
|
||||
tag := f.Tag.Get("capnp")
|
||||
p.tagged = tag != ""
|
||||
tname, opts := nextOpt(tag)
|
||||
switch tname {
|
||||
case "-":
|
||||
// omitted field
|
||||
case "":
|
||||
if f.Anonymous && isStructOrStructPtr(f.Type) {
|
||||
p.typ = embedField
|
||||
return p
|
||||
}
|
||||
if hasDiscrim && f.Name == "Which" {
|
||||
p.typ = whichField
|
||||
for len(opts) > 0 {
|
||||
var curr string
|
||||
curr, opts = nextOpt(opts)
|
||||
if strings.HasPrefix(curr, "which=") {
|
||||
p.fixedWhich = strings.TrimPrefix(curr, "which=")
|
||||
break
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
// TODO(light): check it's uppercase.
|
||||
x := f.Name[0] - 'A' + 'a'
|
||||
p.schemaName = string(x) + f.Name[1:]
|
||||
default:
|
||||
p.schemaName = tname
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func nextOpt(opts string) (head, tail string) {
|
||||
i := strings.Index(opts, ",")
|
||||
if i == -1 {
|
||||
return opts, ""
|
||||
}
|
||||
return opts[:i], opts[i+1:]
|
||||
}
|
||||
|
||||
type fieldLoc struct {
|
||||
i int
|
||||
path []int
|
||||
}
|
||||
|
||||
func (loc fieldLoc) depth() int {
|
||||
if len(loc.path) > 0 {
|
||||
return len(loc.path)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (loc fieldLoc) sub(i int) fieldLoc {
|
||||
n := len(loc.path)
|
||||
switch {
|
||||
case !loc.isValid():
|
||||
return fieldLoc{i: i}
|
||||
case n > 0:
|
||||
p := make([]int, n+1)
|
||||
copy(p, loc.path)
|
||||
p[n] = i
|
||||
return fieldLoc{path: p}
|
||||
default:
|
||||
return fieldLoc{path: []int{loc.i, i}}
|
||||
}
|
||||
}
|
||||
|
||||
func (loc fieldLoc) isValid() bool {
|
||||
return loc.i >= 0
|
||||
}
|
||||
|
||||
type structProps struct {
|
||||
fields []fieldLoc
|
||||
whichLoc fieldLoc // i == -1: none; i == -2: fixed
|
||||
fixedWhich uint16
|
||||
}
|
||||
|
||||
func mapStruct(t reflect.Type, n schema.Node) (structProps, error) {
|
||||
fields, err := n.StructNode().Fields()
|
||||
if err != nil {
|
||||
return structProps{}, err
|
||||
}
|
||||
sp := structProps{
|
||||
fields: make([]fieldLoc, fields.Len()),
|
||||
whichLoc: fieldLoc{i: -1},
|
||||
}
|
||||
for i := range sp.fields {
|
||||
sp.fields[i] = fieldLoc{i: -1}
|
||||
}
|
||||
sm := structMapper{
|
||||
sp: &sp,
|
||||
t: t,
|
||||
hasDiscrim: hasDiscriminant(n),
|
||||
fields: fields,
|
||||
}
|
||||
if err := sm.visit(fieldLoc{i: -1}); err != nil {
|
||||
return structProps{}, err
|
||||
}
|
||||
for len(sm.embedQueue) > 0 {
|
||||
loc := sm.embedQueue[0]
|
||||
copy(sm.embedQueue, sm.embedQueue[1:])
|
||||
sm.embedQueue = sm.embedQueue[:len(sm.embedQueue)-1]
|
||||
if err := sm.visit(loc); err != nil {
|
||||
return structProps{}, err
|
||||
}
|
||||
}
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
type structMapper struct {
|
||||
sp *structProps
|
||||
t reflect.Type
|
||||
hasDiscrim bool
|
||||
fields schema.Field_List
|
||||
embedQueue []fieldLoc
|
||||
}
|
||||
|
||||
func (sm *structMapper) visit(base fieldLoc) error {
|
||||
t := sm.t
|
||||
if base.isValid() {
|
||||
t = typeFieldByLoc(t, base).Type
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
}
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
// unexported field
|
||||
continue
|
||||
}
|
||||
loc := base.sub(i)
|
||||
p := parseField(f, sm.hasDiscrim)
|
||||
if p.typ == embedField {
|
||||
sm.embedQueue = append(sm.embedQueue, loc)
|
||||
continue
|
||||
}
|
||||
if err := sm.visitField(loc, f, p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *structMapper) visitField(loc fieldLoc, f reflect.StructField, p fieldProps) error {
|
||||
switch p.typ {
|
||||
case mappedField:
|
||||
if p.schemaName == "" {
|
||||
return nil
|
||||
}
|
||||
fi := fieldIndex(sm.fields, p.schemaName)
|
||||
if fi < 0 {
|
||||
return fmt.Errorf("%v has unknown field %s, maps to %s", sm.t, f.Name, p.schemaName)
|
||||
}
|
||||
switch oldloc := sm.sp.fields[fi]; {
|
||||
case oldloc.i == -2:
|
||||
// Prior tag collision, do nothing.
|
||||
case oldloc.i == -3 && p.tagged && loc.depth() == len(oldloc.path):
|
||||
// A tagged field wins over untagged fields.
|
||||
sm.sp.fields[fi] = loc
|
||||
case oldloc.isValid() && oldloc.depth() < loc.depth():
|
||||
// This is deeper, don't override.
|
||||
case oldloc.isValid() && oldloc.depth() == loc.depth():
|
||||
oldp := parseField(typeFieldByLoc(sm.t, oldloc), sm.hasDiscrim)
|
||||
if oldp.tagged && p.tagged {
|
||||
// Tag collision
|
||||
sm.sp.fields[fi] = fieldLoc{i: -2}
|
||||
} else if p.tagged {
|
||||
sm.sp.fields[fi] = loc
|
||||
} else if !oldp.tagged {
|
||||
// Multiple untagged fields. Keep path, because we need it for depth.
|
||||
sm.sp.fields[fi].i = -3
|
||||
}
|
||||
default:
|
||||
sm.sp.fields[fi] = loc
|
||||
}
|
||||
case whichField:
|
||||
if sm.sp.whichLoc.i != -1 {
|
||||
return fmt.Errorf("%v embeds multiple Which fields", sm.t)
|
||||
}
|
||||
switch {
|
||||
case p.fixedWhich != "":
|
||||
fi := fieldIndex(sm.fields, p.fixedWhich)
|
||||
if fi < 0 {
|
||||
return fmt.Errorf("%v.Which is tagged with unknown field %s", sm.t, p.fixedWhich)
|
||||
}
|
||||
dv := sm.fields.At(fi).DiscriminantValue()
|
||||
if dv == schema.Field_noDiscriminant {
|
||||
return fmt.Errorf("%v.Which is tagged with non-union field %s", sm.t, p.fixedWhich)
|
||||
}
|
||||
sm.sp.whichLoc = fieldLoc{i: -2}
|
||||
sm.sp.fixedWhich = dv
|
||||
case f.Type.Kind() != reflect.Uint16:
|
||||
return fmt.Errorf("%v.Which is type %v, not uint16", sm.t, f.Type)
|
||||
default:
|
||||
sm.sp.whichLoc = loc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fieldBySchemaName returns the field for the given name.
|
||||
// Returns an invalid value if the field was not found or it is
|
||||
// contained inside a nil anonymous struct pointer.
|
||||
func (sp structProps) fieldByOrdinal(val reflect.Value, i int) reflect.Value {
|
||||
return fieldByLoc(val, sp.fields[i], false)
|
||||
}
|
||||
|
||||
// makeFieldBySchemaName returns the field for the given name, creating
|
||||
// its parent anonymous structs if necessary. Returns an invalid value
|
||||
// if the field was not found.
|
||||
func (sp structProps) makeFieldByOrdinal(val reflect.Value, i int) reflect.Value {
|
||||
return fieldByLoc(val, sp.fields[i], true)
|
||||
}
|
||||
|
||||
// which returns the value of the discriminator field.
|
||||
func (sp structProps) which(val reflect.Value) (discrim uint16, ok bool) {
|
||||
if sp.whichLoc.i == -2 {
|
||||
return sp.fixedWhich, true
|
||||
}
|
||||
f := fieldByLoc(val, sp.whichLoc, false)
|
||||
if !f.IsValid() {
|
||||
return 0, false
|
||||
}
|
||||
return uint16(f.Uint()), true
|
||||
}
|
||||
|
||||
// setWhich sets the value of the discriminator field, creating its
|
||||
// parent anonymous structs if necessary. Returns whether the struct
|
||||
// had a field to set.
|
||||
func (sp structProps) setWhich(val reflect.Value, discrim uint16) error {
|
||||
if sp.whichLoc.i == -2 {
|
||||
if discrim != sp.fixedWhich {
|
||||
return fmt.Errorf("extract union field @%d into %v; expected @%d", discrim, val.Type(), sp.fixedWhich)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
f := fieldByLoc(val, sp.whichLoc, true)
|
||||
if !f.IsValid() {
|
||||
return noWhichError{val.Type()}
|
||||
}
|
||||
f.SetUint(uint64(discrim))
|
||||
return nil
|
||||
}
|
||||
|
||||
type noWhichError struct {
|
||||
t reflect.Type
|
||||
}
|
||||
|
||||
func (e noWhichError) Error() string {
|
||||
return fmt.Sprintf("%v has no field Which", e.t)
|
||||
}
|
||||
|
||||
func isNoWhichError(e error) bool {
|
||||
_, ok := e.(noWhichError)
|
||||
return ok
|
||||
}
|
||||
|
||||
func fieldByLoc(val reflect.Value, loc fieldLoc, mkparents bool) reflect.Value {
|
||||
if !loc.isValid() {
|
||||
return reflect.Value{}
|
||||
}
|
||||
if len(loc.path) > 0 {
|
||||
for i, x := range loc.path {
|
||||
if i > 0 {
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
if !mkparents {
|
||||
return reflect.Value{}
|
||||
}
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
}
|
||||
val = val.Field(x)
|
||||
}
|
||||
return val
|
||||
}
|
||||
return val.Field(loc.i)
|
||||
}
|
||||
|
||||
func typeFieldByLoc(t reflect.Type, loc fieldLoc) reflect.StructField {
|
||||
if len(loc.path) > 0 {
|
||||
return t.FieldByIndex(loc.path)
|
||||
}
|
||||
return t.Field(loc.i)
|
||||
}
|
||||
|
||||
func hasDiscriminant(n schema.Node) bool {
|
||||
return n.Which() == schema.Node_Which_structNode && n.StructNode().DiscriminantCount() > 0
|
||||
}
|
||||
|
||||
func shortDisplayName(n schema.Node) []byte {
|
||||
dn, _ := n.DisplayNameBytes()
|
||||
return dn[n.DisplayNamePrefixLength():]
|
||||
}
|
||||
|
||||
func fieldIndex(fields schema.Field_List, name string) int {
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
b, _ := fields.At(i).NameBytes()
|
||||
if bytesStrEqual(b, name) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func bytesStrEqual(b []byte, s string) bool {
|
||||
if len(b) != len(s) {
|
||||
return false
|
||||
}
|
||||
for i := range b {
|
||||
if b[i] != s[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isStructOrStructPtr(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Struct || t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||
}
|
485
vendor/zombiezen.com/go/capnproto2/pogs/insert.go
generated
vendored
Normal file
485
vendor/zombiezen.com/go/capnproto2/pogs/insert.go
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/internal/nodemap"
|
||||
"zombiezen.com/go/capnproto2/internal/schema"
|
||||
)
|
||||
|
||||
// Insert copies val, a pointer to a Go struct, into s.
|
||||
func Insert(typeID uint64, s capnp.Struct, val interface{}) error {
|
||||
ins := new(inserter)
|
||||
err := ins.insertStruct(typeID, s, reflect.ValueOf(val))
|
||||
if err != nil {
|
||||
return fmt.Errorf("pogs: insert @%#x: %v", typeID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type inserter struct {
|
||||
nodes nodemap.Map
|
||||
}
|
||||
|
||||
func (ins *inserter) insertStruct(typeID uint64, s capnp.Struct, val reflect.Value) error {
|
||||
if val.Kind() == reflect.Ptr {
|
||||
// TODO(light): ignore if nil?
|
||||
val = val.Elem()
|
||||
}
|
||||
if val.Kind() != reflect.Struct {
|
||||
return fmt.Errorf("can't insert %v into a struct", val.Kind())
|
||||
}
|
||||
n, err := ins.nodes.Find(typeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !n.IsValid() || n.Which() != schema.Node_Which_structNode {
|
||||
return fmt.Errorf("cannot find struct type %#x", typeID)
|
||||
}
|
||||
props, err := mapStruct(val.Type(), n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't insert into %v: %v", val.Type(), err)
|
||||
}
|
||||
var discriminant uint16
|
||||
hasWhich := false
|
||||
if hasDiscriminant(n) {
|
||||
discriminant, hasWhich = props.which(val)
|
||||
if hasWhich {
|
||||
off := capnp.DataOffset(n.StructNode().DiscriminantOffset() * 2)
|
||||
if s.Size().DataSize < capnp.Size(off+2) {
|
||||
return fmt.Errorf("can't set discriminant for %s: allocated struct is too small", shortDisplayName(n))
|
||||
}
|
||||
s.SetUint16(off, discriminant)
|
||||
}
|
||||
}
|
||||
fields, err := n.StructNode().Fields()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
f := fields.At(i)
|
||||
vf := props.fieldByOrdinal(val, i)
|
||||
if !vf.IsValid() {
|
||||
// Don't have a field for this.
|
||||
continue
|
||||
}
|
||||
if dv := f.DiscriminantValue(); dv != schema.Field_noDiscriminant {
|
||||
if !hasWhich {
|
||||
sname, _ := f.NameBytes()
|
||||
return fmt.Errorf("can't insert %s from %v: has union field %s but no Which field", shortDisplayName(n), val.Type(), sname)
|
||||
}
|
||||
if dv != discriminant {
|
||||
continue
|
||||
}
|
||||
}
|
||||
switch f.Which() {
|
||||
case schema.Field_Which_slot:
|
||||
if err := ins.insertField(s, f, vf); err != nil {
|
||||
return err
|
||||
}
|
||||
case schema.Field_Which_group:
|
||||
if err := ins.insertStruct(f.Group().TypeId(), s, vf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ins *inserter) insertField(s capnp.Struct, f schema.Field, val reflect.Value) error {
|
||||
typ, err := f.Slot().Type()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dv, err := f.Slot().DefaultValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dv.IsValid() && int(typ.Which()) != int(dv.Which()) {
|
||||
name, _ := f.NameBytes()
|
||||
return fmt.Errorf("insert field %s: default value is a %v, want %v", name, dv.Which(), typ.Which())
|
||||
}
|
||||
if !isTypeMatch(val.Type(), typ) {
|
||||
name, _ := f.NameBytes()
|
||||
return fmt.Errorf("can't insert field %s of type Go %v into a %v", name, val.Type(), typ.Which())
|
||||
}
|
||||
if !isFieldInBounds(s.Size(), f.Slot().Offset(), typ) {
|
||||
name, _ := f.NameBytes()
|
||||
return fmt.Errorf("can't insert field %s: allocated struct is too small", name)
|
||||
}
|
||||
switch typ.Which() {
|
||||
case schema.Type_Which_bool:
|
||||
v := val.Bool()
|
||||
d := dv.Bool()
|
||||
s.SetBit(capnp.BitOffset(f.Slot().Offset()), v != d) // != acts as XOR
|
||||
case schema.Type_Which_int8:
|
||||
v := int8(val.Int())
|
||||
d := dv.Int8()
|
||||
s.SetUint8(capnp.DataOffset(f.Slot().Offset()), uint8(v^d))
|
||||
case schema.Type_Which_int16:
|
||||
v := int16(val.Int())
|
||||
d := dv.Int16()
|
||||
s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), uint16(v^d))
|
||||
case schema.Type_Which_int32:
|
||||
v := int32(val.Int())
|
||||
d := dv.Int32()
|
||||
s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), uint32(v^d))
|
||||
case schema.Type_Which_int64:
|
||||
v := val.Int()
|
||||
d := dv.Int64()
|
||||
s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), uint64(v^d))
|
||||
case schema.Type_Which_uint8:
|
||||
v := uint8(val.Uint())
|
||||
d := dv.Uint8()
|
||||
s.SetUint8(capnp.DataOffset(f.Slot().Offset()), v^d)
|
||||
case schema.Type_Which_uint16:
|
||||
v := uint16(val.Uint())
|
||||
d := dv.Uint16()
|
||||
s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), v^d)
|
||||
case schema.Type_Which_enum:
|
||||
v := uint16(val.Uint())
|
||||
d := dv.Enum()
|
||||
s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), v^d)
|
||||
case schema.Type_Which_uint32:
|
||||
v := uint32(val.Uint())
|
||||
d := dv.Uint32()
|
||||
s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), v^d)
|
||||
case schema.Type_Which_uint64:
|
||||
v := val.Uint()
|
||||
d := dv.Uint64()
|
||||
s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), v^d)
|
||||
case schema.Type_Which_float32:
|
||||
v := math.Float32bits(float32(val.Float()))
|
||||
d := math.Float32bits(dv.Float32())
|
||||
s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), v^d)
|
||||
case schema.Type_Which_float64:
|
||||
v := math.Float64bits(val.Float())
|
||||
d := uint64(math.Float64bits(dv.Float64()))
|
||||
s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), v^d)
|
||||
case schema.Type_Which_text:
|
||||
off := uint16(f.Slot().Offset())
|
||||
if val.Len() == 0 {
|
||||
if !isEmptyValue(dv) {
|
||||
return s.SetNewText(off, "")
|
||||
}
|
||||
return s.SetText(off, "")
|
||||
}
|
||||
if val.Kind() == reflect.String {
|
||||
return s.SetText(off, val.String())
|
||||
} else {
|
||||
return s.SetTextFromBytes(off, val.Bytes())
|
||||
}
|
||||
case schema.Type_Which_data:
|
||||
b := val.Bytes()
|
||||
if b == nil && !isEmptyValue(dv) {
|
||||
b = []byte{}
|
||||
}
|
||||
off := uint16(f.Slot().Offset())
|
||||
return s.SetData(off, b)
|
||||
case schema.Type_Which_structType:
|
||||
off := uint16(f.Slot().Offset())
|
||||
sval := val
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
return s.SetPtr(off, capnp.Ptr{})
|
||||
}
|
||||
sval = val.Elem()
|
||||
}
|
||||
id := typ.StructType().TypeId()
|
||||
sz, err := ins.structSize(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss, err := capnp.NewStruct(s.Segment(), sz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.SetPtr(off, ss.ToPtr()); err != nil {
|
||||
return err
|
||||
}
|
||||
return ins.insertStruct(id, ss, sval)
|
||||
case schema.Type_Which_list:
|
||||
off := uint16(f.Slot().Offset())
|
||||
if val.IsNil() && isEmptyValue(dv) {
|
||||
return s.SetPtr(off, capnp.Ptr{})
|
||||
}
|
||||
elem, err := typ.List().ElementType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l, err := ins.newList(s.Segment(), elem, int32(val.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.SetPtr(off, l.ToPtr()); err != nil {
|
||||
return err
|
||||
}
|
||||
return ins.insertList(l, typ, val)
|
||||
case schema.Type_Which_interface:
|
||||
off := uint16(f.Slot().Offset())
|
||||
ptr := capPtr(s.Segment(), val)
|
||||
if err := s.SetPtr(off, ptr); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown field type %v", typ.Which())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func capPtr(seg *capnp.Segment, val reflect.Value) capnp.Ptr {
|
||||
client, ok := val.Interface().(capnp.Client)
|
||||
if !ok {
|
||||
client, ok = val.FieldByName("Client").Interface().(capnp.Client)
|
||||
if !ok {
|
||||
// interface is nil.
|
||||
return capnp.Ptr{}
|
||||
}
|
||||
}
|
||||
cap := seg.Message().AddCap(client)
|
||||
iface := capnp.NewInterface(seg, cap)
|
||||
return iface.ToPtr()
|
||||
}
|
||||
|
||||
func (ins *inserter) insertList(l capnp.List, typ schema.Type, val reflect.Value) error {
|
||||
elem, err := typ.List().ElementType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isTypeMatch(val.Type(), typ) {
|
||||
// TODO(light): the error won't be that useful for nested lists.
|
||||
return fmt.Errorf("can't insert Go %v into a %v list", val.Type(), elem.Which())
|
||||
}
|
||||
n := val.Len()
|
||||
switch elem.Which() {
|
||||
case schema.Type_Which_void:
|
||||
case schema.Type_Which_bool:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.BitList{List: l}.Set(i, val.Index(i).Bool())
|
||||
}
|
||||
case schema.Type_Which_int8:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Int8List{List: l}.Set(i, int8(val.Index(i).Int()))
|
||||
}
|
||||
case schema.Type_Which_int16:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Int16List{List: l}.Set(i, int16(val.Index(i).Int()))
|
||||
}
|
||||
case schema.Type_Which_int32:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Int32List{List: l}.Set(i, int32(val.Index(i).Int()))
|
||||
}
|
||||
case schema.Type_Which_int64:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Int64List{List: l}.Set(i, val.Index(i).Int())
|
||||
}
|
||||
case schema.Type_Which_uint8:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.UInt8List{List: l}.Set(i, uint8(val.Index(i).Uint()))
|
||||
}
|
||||
case schema.Type_Which_uint16, schema.Type_Which_enum:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.UInt16List{List: l}.Set(i, uint16(val.Index(i).Uint()))
|
||||
}
|
||||
case schema.Type_Which_uint32:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.UInt32List{List: l}.Set(i, uint32(val.Index(i).Uint()))
|
||||
}
|
||||
case schema.Type_Which_uint64:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.UInt64List{List: l}.Set(i, val.Index(i).Uint())
|
||||
}
|
||||
case schema.Type_Which_float32:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Float32List{List: l}.Set(i, float32(val.Index(i).Float()))
|
||||
}
|
||||
case schema.Type_Which_float64:
|
||||
for i := 0; i < n; i++ {
|
||||
capnp.Float64List{List: l}.Set(i, val.Index(i).Float())
|
||||
}
|
||||
case schema.Type_Which_text:
|
||||
if val.Type().Elem().Kind() == reflect.String {
|
||||
for i := 0; i < n; i++ {
|
||||
err := capnp.TextList{List: l}.Set(i, val.Index(i).String())
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < n; i++ {
|
||||
b := val.Index(i).Bytes()
|
||||
if len(b) == 0 {
|
||||
err := capnp.PointerList{List: l}.SetPtr(i, capnp.Ptr{})
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
t, err := capnp.NewTextFromBytes(l.Segment(), b)
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
err = capnp.PointerList{List: l}.SetPtr(i, t.ToPtr())
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_data:
|
||||
for i := 0; i < n; i++ {
|
||||
b := val.Index(i).Bytes()
|
||||
if len(b) == 0 {
|
||||
err := capnp.PointerList{List: l}.SetPtr(i, capnp.Ptr{})
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := capnp.DataList{List: l}.Set(i, b)
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_list:
|
||||
pl := capnp.PointerList{List: l}
|
||||
for i := 0; i < n; i++ {
|
||||
vi := val.Index(i)
|
||||
if vi.IsNil() {
|
||||
if err := pl.SetPtr(i, capnp.Ptr{}); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
ee, err := elem.List().ElementType()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
li, err := ins.newList(l.Segment(), ee, int32(vi.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pl.SetPtr(i, li.ToPtr()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ins.insertList(li, elem, vi); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_structType:
|
||||
id := elem.StructType().TypeId()
|
||||
for i := 0; i < n; i++ {
|
||||
err := ins.insertStruct(id, l.Struct(i), val.Index(i))
|
||||
if err != nil {
|
||||
// TODO(light): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
case schema.Type_Which_interface:
|
||||
pl := capnp.PointerList{List: l}
|
||||
for i := 0; i < n; i++ {
|
||||
ptr := capPtr(l.Segment(), val.Index(i))
|
||||
if err := pl.SetPtr(i, ptr); err != nil {
|
||||
// TODO(zenhack): collect errors and finish
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown list type %v", elem.Which())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ins *inserter) newList(s *capnp.Segment, t schema.Type, len int32) (capnp.List, error) {
|
||||
switch t.Which() {
|
||||
case schema.Type_Which_void:
|
||||
l := capnp.NewVoidList(s, len)
|
||||
return l.List, nil
|
||||
case schema.Type_Which_bool:
|
||||
l, err := capnp.NewBitList(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_int8, schema.Type_Which_uint8:
|
||||
l, err := capnp.NewUInt8List(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_int16, schema.Type_Which_uint16, schema.Type_Which_enum:
|
||||
l, err := capnp.NewUInt16List(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_int32, schema.Type_Which_uint32, schema.Type_Which_float32:
|
||||
l, err := capnp.NewUInt32List(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_int64, schema.Type_Which_uint64, schema.Type_Which_float64:
|
||||
l, err := capnp.NewUInt64List(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_text, schema.Type_Which_data, schema.Type_Which_list, schema.Type_Which_interface, schema.Type_Which_anyPointer:
|
||||
l, err := capnp.NewPointerList(s, len)
|
||||
return l.List, err
|
||||
case schema.Type_Which_structType:
|
||||
sz, err := ins.structSize(t.StructType().TypeId())
|
||||
if err != nil {
|
||||
return capnp.List{}, err
|
||||
}
|
||||
return capnp.NewCompositeList(s, sz, len)
|
||||
default:
|
||||
return capnp.List{}, fmt.Errorf("new list: unknown element type: %v", t.Which())
|
||||
}
|
||||
}
|
||||
|
||||
func (ins *inserter) structSize(id uint64) (capnp.ObjectSize, error) {
|
||||
n, err := ins.nodes.Find(id)
|
||||
if err != nil {
|
||||
return capnp.ObjectSize{}, err
|
||||
}
|
||||
if n.Which() != schema.Node_Which_structNode {
|
||||
return capnp.ObjectSize{}, fmt.Errorf("insert struct: sizing: node @%#x is not a struct", id)
|
||||
}
|
||||
return capnp.ObjectSize{
|
||||
DataSize: capnp.Size(n.StructNode().DataWordCount()) * 8,
|
||||
PointerCount: n.StructNode().PointerCount(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func isFieldInBounds(sz capnp.ObjectSize, off uint32, t schema.Type) bool {
|
||||
switch t.Which() {
|
||||
case schema.Type_Which_void:
|
||||
return true
|
||||
case schema.Type_Which_bool:
|
||||
return sz.DataSize >= capnp.Size(off/8+1)
|
||||
case schema.Type_Which_int8, schema.Type_Which_uint8:
|
||||
return sz.DataSize >= capnp.Size(off+1)
|
||||
case schema.Type_Which_int16, schema.Type_Which_uint16, schema.Type_Which_enum:
|
||||
return sz.DataSize >= capnp.Size(off+1)*2
|
||||
case schema.Type_Which_int32, schema.Type_Which_uint32, schema.Type_Which_float32:
|
||||
return sz.DataSize >= capnp.Size(off+1)*4
|
||||
case schema.Type_Which_int64, schema.Type_Which_uint64, schema.Type_Which_float64:
|
||||
return sz.DataSize >= capnp.Size(off+1)*8
|
||||
case schema.Type_Which_text, schema.Type_Which_data, schema.Type_Which_list, schema.Type_Which_structType, schema.Type_Which_interface, schema.Type_Which_anyPointer:
|
||||
return sz.PointerCount >= uint16(off+1)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isEmptyValue(v schema.Value) bool {
|
||||
if !v.IsValid() {
|
||||
return false
|
||||
}
|
||||
switch v.Which() {
|
||||
case schema.Value_Which_text:
|
||||
b, _ := v.TextBytes()
|
||||
return len(b) == 0
|
||||
case schema.Value_Which_data:
|
||||
b, _ := v.Data()
|
||||
return len(b) == 0
|
||||
case schema.Value_Which_list:
|
||||
p, _ := v.ListPtr()
|
||||
return p.List().Len() == 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
172
vendor/zombiezen.com/go/capnproto2/pogs/interface_test.go
generated
vendored
Normal file
172
vendor/zombiezen.com/go/capnproto2/pogs/interface_test.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package pogs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"zombiezen.com/go/capnproto2"
|
||||
air "zombiezen.com/go/capnproto2/internal/aircraftlib"
|
||||
)
|
||||
|
||||
type simpleEcho struct{}
|
||||
|
||||
func checkFatal(t *testing.T, name string, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("%s for TestInsertIFace: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s simpleEcho) Echo(p air.Echo_echo) error {
|
||||
text, err := p.Params.In()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Results.SetOut(text)
|
||||
return nil
|
||||
}
|
||||
|
||||
type EchoBase struct {
|
||||
Echo air.Echo
|
||||
}
|
||||
|
||||
type EchoBases struct {
|
||||
Bases []EchoBase
|
||||
}
|
||||
|
||||
type Hoth struct {
|
||||
Base EchoBase
|
||||
}
|
||||
|
||||
func TestInsertIFace(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
checkFatal(t, "NewMessage", err)
|
||||
h, err := air.NewRootHoth(seg)
|
||||
checkFatal(t, "NewRootHoth", err)
|
||||
err = Insert(air.Hoth_TypeID, h.Struct, Hoth{
|
||||
Base: EchoBase{Echo: air.Echo_ServerToClient(simpleEcho{})},
|
||||
})
|
||||
checkFatal(t, "Insert", err)
|
||||
base, err := h.Base()
|
||||
checkFatal(t, "h.Base", err)
|
||||
echo := base.Echo()
|
||||
|
||||
testEcho(t, echo)
|
||||
}
|
||||
|
||||
func TestInsertListIFace(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
checkFatal(t, "NewMessage", err)
|
||||
wrapper, err := air.NewEchoBases(seg)
|
||||
checkFatal(t, "NewEchoBases", err)
|
||||
err = Insert(air.EchoBases_TypeID, wrapper.Struct, EchoBases{
|
||||
Bases: []EchoBase{
|
||||
{Echo: air.Echo_ServerToClient(simpleEcho{})},
|
||||
{Echo: air.Echo_ServerToClient(simpleEcho{})},
|
||||
},
|
||||
})
|
||||
checkFatal(t, "Insert", err)
|
||||
bases, err := wrapper.Bases()
|
||||
checkFatal(t, "Bases", err)
|
||||
for i := 0; i < bases.Len(); i++ {
|
||||
testEcho(t, bases.At(i).Echo())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInsertNilInterface(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
checkFatal(t, "NewMessage", err)
|
||||
h, err := air.NewRootHoth(seg)
|
||||
checkFatal(t, "NewRootHoth", err)
|
||||
err = Insert(air.Hoth_TypeID, h.Struct, Hoth{
|
||||
Base: EchoBase{Echo: air.Echo{Client: nil}},
|
||||
})
|
||||
checkFatal(t, "Insert", err)
|
||||
base, err := h.Base()
|
||||
checkFatal(t, "h.Base", err)
|
||||
echo := base.Echo()
|
||||
if echo.Client != nil {
|
||||
t.Fatalf("Expected nil client, but got %v", echo.Client)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractIFace(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
checkFatal(t, "NewMessage", err)
|
||||
h, err := air.NewRootHoth(seg)
|
||||
checkFatal(t, "NewRootHoth", err)
|
||||
base, err := air.NewEchoBase(seg)
|
||||
checkFatal(t, "NewEchoBase", err)
|
||||
h.SetBase(base)
|
||||
base.SetEcho(air.Echo_ServerToClient(simpleEcho{}))
|
||||
|
||||
extractedHoth := Hoth{}
|
||||
err = Extract(&extractedHoth, air.Hoth_TypeID, h.Struct)
|
||||
checkFatal(t, "Extract", err)
|
||||
|
||||
testEcho(t, extractedHoth.Base.Echo)
|
||||
}
|
||||
|
||||
func TestExtractListIFace(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
checkFatal(t, "NewMessage", err)
|
||||
wrapper, err := air.NewEchoBases(seg)
|
||||
checkFatal(t, "NewEchoBases", err)
|
||||
length := 2
|
||||
list, err := air.NewEchoBase_List(seg, int32(length))
|
||||
checkFatal(t, "NewEchoBase_List", err)
|
||||
for i := 0; i < length; i++ {
|
||||
base, err := air.NewEchoBase(seg)
|
||||
base.SetEcho(air.Echo_ServerToClient(simpleEcho{}))
|
||||
checkFatal(t, "NewEchoBase", err)
|
||||
list.Set(i, base)
|
||||
}
|
||||
wrapper.SetBases(list)
|
||||
|
||||
extractedBases := EchoBases{}
|
||||
err = Extract(&extractedBases, air.EchoBases_TypeID, wrapper.Struct)
|
||||
checkFatal(t, "Extract", err)
|
||||
if extractedBases.Bases == nil {
|
||||
t.Fatal("Bases is nil")
|
||||
}
|
||||
if len(extractedBases.Bases) != length {
|
||||
t.Fatalf("Bases has Wrong length: got %d but wanted %d.",
|
||||
len(extractedBases.Bases), length)
|
||||
}
|
||||
for _, v := range extractedBases.Bases {
|
||||
testEcho(t, v.Echo)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure extract correctly handles missing interfaces.
|
||||
func TestExtractMissingIFace(t *testing.T) {
|
||||
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
|
||||
base, err := air.NewRootEchoBase(seg)
|
||||
checkFatal(t, "NewRootEchoBase", err)
|
||||
|
||||
// Fill the client in, so we know that after extracting, if
|
||||
// it's nil it's because it was *set*, not just left over:
|
||||
extractedBase := EchoBase{Echo: air.Echo_ServerToClient(simpleEcho{})}
|
||||
|
||||
err = Extract(&extractedBase, air.EchoBase_TypeID, base.Struct)
|
||||
checkFatal(t, "Extract", err)
|
||||
if extractedBase.Echo.Client != nil {
|
||||
t.Fatalf("Expected nil client but got %v", extractedBase.Echo.Client)
|
||||
}
|
||||
}
|
||||
|
||||
func testEcho(t *testing.T, echo air.Echo) {
|
||||
expected := "Hello!"
|
||||
result, err := echo.Echo(context.TODO(), func(p air.Echo_echo_Params) error {
|
||||
p.SetIn(expected)
|
||||
return nil
|
||||
}).Struct()
|
||||
checkFatal(t, "Echo", err)
|
||||
actual, err := result.Out()
|
||||
checkFatal(t, "result.Out", err)
|
||||
if actual != expected {
|
||||
t.Fatal("Echo result did not match input; "+
|
||||
"wanted %q but got %q.", expected, actual)
|
||||
}
|
||||
}
|
1472
vendor/zombiezen.com/go/capnproto2/pogs/pogs_test.go
generated
vendored
Normal file
1472
vendor/zombiezen.com/go/capnproto2/pogs/pogs_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user