TUN-528: Move cloudflared into a separate repo

This commit is contained in:
Areg Harutyunyan
2018-05-01 18:45:06 -05:00
parent e8c621a648
commit d06fc520c7
4726 changed files with 1763680 additions and 0 deletions

View File

@@ -0,0 +1 @@
/capnpc-go

View File

@@ -0,0 +1,36 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"capnpc-go.go",
"fileparts.go",
"nodes.go",
"templateparams.go",
"templates.go",
],
importpath = "zombiezen.com/go/capnproto2/capnpc-go",
visibility = ["//visibility:private"],
deps = [
"//:go_default_library",
"//internal/schema:go_default_library",
],
)
go_binary(
name = "capnpc-go",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["capnpc-go_test.go"],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//:go_default_library",
"//encoding/text:go_default_library",
"//internal/schema:go_default_library",
],
)

1208
vendor/zombiezen.com/go/capnproto2/capnpc-go/capnpc-go.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,471 @@
package main
import (
"bytes"
"fmt"
"go/parser"
"go/token"
"io/ioutil"
"path/filepath"
"sort"
"strconv"
"strings"
"testing"
"zombiezen.com/go/capnproto2"
"zombiezen.com/go/capnproto2/encoding/text"
"zombiezen.com/go/capnproto2/internal/schema"
)
func readTestFile(name string) ([]byte, error) {
path := filepath.Join("testdata", name)
return ioutil.ReadFile(path)
}
func mustReadTestFile(t *testing.T, name string) []byte {
data, err := readTestFile(name)
if err != nil {
t.Fatal(err)
}
return data
}
func mustReadGeneratorRequest(t *testing.T, name string) schema.CodeGeneratorRequest {
data := mustReadTestFile(t, name)
msg, err := capnp.Unmarshal(data)
if err != nil {
t.Fatalf("Unmarshaling %s: %v", name, err)
}
req, err := schema.ReadRootCodeGeneratorRequest(msg)
if err != nil {
t.Fatalf("Reading code generator request %s: %v", name, err)
}
return req
}
func TestBuildNodeMap(t *testing.T) {
tests := []struct {
name string
fileID uint64
fileNodes []uint64
}{
{
name: "go.capnp.out",
fileID: 0xd12a1c51fedd6c88,
fileNodes: []uint64{
0xbea97f1023792be0,
0xe130b601260e44b5,
0xc58ad6bd519f935e,
0xa574b41924caefc7,
0xc8768679ec52e012,
0xfa10659ae02f2093,
0xc2b96012172f8df1,
},
},
{
name: "group.capnp.out",
fileID: 0x83c2b5818e83ab19,
fileNodes: []uint64{
0xd119fd352d8ea888, // the struct
0x822357857e5925d4, // the group
},
},
}
for _, test := range tests {
data, err := readTestFile(test.name)
if err != nil {
t.Errorf("readTestFile(%q): %v", test.name, err)
continue
}
msg, err := capnp.Unmarshal(data)
if err != nil {
t.Errorf("Unmarshaling %s: %v", test.name, err)
continue
}
req, err := schema.ReadRootCodeGeneratorRequest(msg)
if err != nil {
t.Errorf("Reading code generator request %s: %v", test.name, err)
continue
}
nodes, err := buildNodeMap(req)
if err != nil {
t.Errorf("%s: buildNodeMap: %v", test.name, err)
}
f := nodes[test.fileID]
if f == nil {
t.Errorf("%s: node map is missing file node @%#x", test.name, test.fileID)
continue
}
if f.Id() != test.fileID {
t.Errorf("%s: node map has ID @%#x for lookup of @%#x", test.name, f.Id(), test.fileID)
}
// Test node.nodes collection
for _, id := range test.fileNodes {
found := false
for _, fn := range f.nodes {
if fn.Id() == id {
found = true
break
}
}
if !found {
t.Errorf("%s: missing @%#x from file nodes", test.name, id)
}
}
// Test map lookup
for _, k := range test.fileNodes {
n := nodes[k]
if n == nil {
t.Errorf("%s: missing @%#x from node map", test.name, k)
}
if n.Id() != k {
t.Errorf("%s: node map has ID @%#x for lookup of @%#x", test.name, n.Id(), k)
}
}
}
}
func TestRemoteScope(t *testing.T) {
type scopeTest struct {
name string
constID uint64
initImports []importSpec
remoteName string
remoteNew string
imports []importSpec
}
tests := []scopeTest{
{
name: "same-file struct",
constID: 0x84efedc75e99768d, // scopes.fooVar
remoteName: "Foo",
remoteNew: "NewFoo",
},
{
name: "different file struct",
constID: 0x836faf1834d91729, // scopes.otherFooVar
remoteName: "otherscopes.Foo",
remoteNew: "otherscopes.NewFoo",
imports: []importSpec{
{name: "otherscopes", path: "zombiezen.com/go/capnproto2/capnpc-go/testdata/otherscopes"},
},
},
{
name: "same-file struct list",
constID: 0xcda2680ec5c921e0, // scopes.fooListVar
remoteName: "Foo_List",
remoteNew: "NewFoo_List",
},
{
name: "different file struct list",
constID: 0x83e7e1b3cd1be338, // scopes.otherFooListVar
remoteName: "otherscopes.Foo_List",
remoteNew: "otherscopes.NewFoo_List",
imports: []importSpec{
{name: "otherscopes", path: "zombiezen.com/go/capnproto2/capnpc-go/testdata/otherscopes"},
},
},
{
name: "built-in Int32 list",
constID: 0xacf3d9917d0bb0f0, // scopes.intList
remoteName: "capnp.Int32List",
remoteNew: "capnp.NewInt32List",
imports: []importSpec{
{name: "capnp", path: "zombiezen.com/go/capnproto2"},
},
},
}
req := mustReadGeneratorRequest(t, "scopes.capnp.out")
nodes, err := buildNodeMap(req)
if err != nil {
t.Fatal("buildNodeMap:", err)
}
collect := func(test scopeTest) (g *generator, typ schema.Type, from *node, ok bool) {
g = newGenerator(0xd68755941d99d05e, nodes, genoptions{})
v := nodes[test.constID]
if v == nil {
t.Errorf("Can't find const @%#x for %s test", test.constID, test.name)
return nil, schema.Type{}, nil, false
}
if v.Which() != schema.Node_Which_const {
t.Errorf("Type of node @%#x in %s test is a %v node; want const. Check the test.", test.constID, test.name, v.Which())
return nil, schema.Type{}, nil, false
}
constType, _ := v.Const().Type()
for _, i := range test.initImports {
g.imports.add(i)
}
return g, constType, v, true
}
for _, test := range tests {
g, typ, from, ok := collect(test)
if !ok {
continue
}
rn, err := g.RemoteTypeName(typ, from)
if err != nil {
t.Errorf("%s: g.RemoteTypeName(nodes[%#x].Const().Type(), nodes[%#x]) error: %v", test.name, test.constID, test.constID, err)
continue
}
if rn != test.remoteName {
t.Errorf("%s: g.RemoteTypeName(nodes[%#x].Const().Type(), nodes[%#x]) = %q; want %q", test.name, test.constID, test.constID, rn, test.remoteName)
continue
}
if !hasExactImports(test.imports, g.imports) {
t.Errorf("%s: g.RemoteTypeName(nodes[%#x].Const().Type(), nodes[%#x]); g.imports = %s; want %s", test.name, test.constID, test.constID, formatImportSpecs(g.imports.usedImports()), formatImportSpecs(test.imports))
continue
}
}
for _, test := range tests {
g, typ, from, ok := collect(test)
if !ok {
continue
}
rn, err := g.RemoteTypeNew(typ, from)
if err != nil {
t.Errorf("%s: g.RemoteTypeNew(nodes[%#x].Const().Type(), nodes[%#x]) error: %v", test.name, test.constID, test.constID, err)
continue
}
if rn != test.remoteNew {
t.Errorf("%s: g.RemoteTypeNew(nodes[%#x].Const().Type(), nodes[%#x]) = %q; want %q", test.name, test.constID, test.constID, rn, test.remoteNew)
continue
}
if !hasExactImports(test.imports, g.imports) {
t.Errorf("%s: g.RemoteTypeNew(nodes[%#x].Const().Type(), nodes[%#x]); g.imports = %s; want %s", test.name, test.constID, test.constID, formatImportSpecs(g.imports.usedImports()), formatImportSpecs(test.imports))
continue
}
}
}
func hasExactImports(specs []importSpec, imp imports) bool {
used := imp.usedImports()
if len(used) != len(specs) {
return false
}
outer:
for i := range specs {
for j := range used {
if specs[i] == used[j] {
continue outer
}
}
return false
}
return true
}
func formatImportSpecs(specs []importSpec) string {
var buf bytes.Buffer
for i, s := range specs {
if i > 0 {
buf.WriteString("; ")
}
buf.WriteString(s.String())
}
return buf.String()
}
func TestDefineConstNodes(t *testing.T) {
req := mustReadGeneratorRequest(t, "const.capnp.out")
nodes, err := buildNodeMap(req)
if err != nil {
t.Fatal("buildNodeMap:", err)
}
g := newGenerator(0xc260cb50ae622e10, nodes, genoptions{})
getCalls := traceGenerator(g)
err = g.defineConstNodes(nodes[0xc260cb50ae622e10].nodes)
if err != nil {
t.Fatal("defineConstNodes:", err)
}
calls := getCalls()
if len(calls) != 1 {
t.Fatalf("defineConstNodes called %d templates; want 1", len(calls))
}
p, ok := calls[0].params.(constantsParams)
if calls[0].name != "constants" || !ok {
t.Fatalf("defineConstNodes rendered %v; want render of constants template", calls[0])
}
if !containsExactlyIDs(p.Consts, 0xda96e2255811b258) {
t.Errorf("defineConstNodes rendered Consts %s", nodeListString(p.Consts))
}
if !containsExactlyIDs(p.Vars, 0xe0a385c7be1fea4d) {
t.Errorf("defineConstNodes rendered Vars %s", nodeListString(p.Vars))
}
}
func TestDefineFile(t *testing.T) {
// Sanity check to make sure codegen produces parseable Go.
const iterations = 3
defaultOptions := genoptions{
promises: true,
schemas: true,
structStrings: true,
}
tests := []struct {
fileID uint64
fname string
opts genoptions
}{
{0x832bcc6686a26d56, "aircraft.capnp.out", defaultOptions},
{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
promises: false,
schemas: false,
structStrings: false,
}},
{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
promises: true,
schemas: false,
structStrings: false,
}},
{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
promises: false,
schemas: true,
structStrings: false,
}},
{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
promises: true,
schemas: true,
structStrings: false,
}},
{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
promises: false,
schemas: true,
structStrings: true,
}},
{0x83c2b5818e83ab19, "group.capnp.out", defaultOptions},
{0xb312981b2552a250, "rpc.capnp.out", defaultOptions},
{0xd68755941d99d05e, "scopes.capnp.out", defaultOptions},
{0xecd50d792c3d9992, "util.capnp.out", defaultOptions},
}
for _, test := range tests {
data, err := readTestFile(test.fname)
if err != nil {
t.Errorf("reading %s: %v", test.fname, err)
continue
}
msg, err := capnp.Unmarshal(data)
if err != nil {
t.Errorf("Unmarshaling %s: %v", test.fname, err)
continue
}
req, err := schema.ReadRootCodeGeneratorRequest(msg)
if err != nil {
t.Errorf("Reading code generator request %s: %v", test.fname, err)
continue
}
nodes, err := buildNodeMap(req)
if err != nil {
t.Errorf("buildNodeMap %s: %v", test.fname, err)
continue
}
g := newGenerator(test.fileID, nodes, test.opts)
if err := g.defineFile(); err != nil {
t.Errorf("defineFile %s %+v: %v", test.fname, test.opts, err)
continue
}
src := g.generate()
if _, err := parser.ParseFile(token.NewFileSet(), test.fname+".go", src, 0); err != nil {
// TODO(light): log src
t.Errorf("generate %s %+v failed to parse: %v", test.fname, test.opts, err)
}
// Generation should be deterministic between runs.
for i := 0; i < iterations-1; i++ {
g := newGenerator(test.fileID, nodes, test.opts)
if err := g.defineFile(); err != nil {
t.Errorf("defineFile %s %+v [iteration %d]: %v", test.fname, test.opts, i+2, err)
continue
}
src2 := g.generate()
if !bytes.Equal(src, src2) {
t.Errorf("defineFile %s %+v [iteration %d] did not match iteration 1: non-deterministic", test.fname, test.opts, i+2)
}
}
}
}
func TestSchemaVarLiteral(t *testing.T) {
tests := []string{
"",
"foo",
"deadbeefdeadbeef",
"deadbeefdeadbeefdeadbeef",
"\x00\x00",
"\xff\xff",
"\n",
" ~\"\\",
"\xff\xff\x27\xa1\xe3\xf1",
}
for _, test := range tests {
got := schemaVarParams{schema: []byte(test)}.SchemaLiteral()
u, err := strconv.Unquote(strings.Replace(got, "\" +\n\t\"", "", -1))
if err != nil {
t.Errorf("schema literal of %q does not parse: %v\n\tproduced: %s", test, err, got)
} else if u != test {
t.Errorf("schema literal of %q != %s", test, got)
}
}
}
type traceRenderer struct {
renderer
calls []renderCall
}
func traceGenerator(g *generator) (getCalls func() []renderCall) {
tr := &traceRenderer{renderer: g.r}
g.r = tr
return func() []renderCall { return tr.calls }
}
func (tr *traceRenderer) Render(name string, params interface{}) error {
tr.calls = append(tr.calls, renderCall{name, params})
return tr.renderer.Render(name, params)
}
type renderCall struct {
name string
params interface{}
}
func (rc renderCall) String() string {
return fmt.Sprintf("{%q %#v}", rc.name, rc.params)
}
func containsExactlyIDs(nodes []*node, ids ...uint64) bool {
if len(nodes) != len(ids) {
return false
}
sorted := make([]uint64, len(ids))
copy(sorted, ids)
sort.Sort(uint64Slice(sorted))
actual := make([]uint64, len(nodes))
for i := range nodes {
actual[i] = nodes[i].Id()
}
sort.Sort(uint64Slice(actual))
for i := range sorted {
if actual[i] != sorted[i] {
return false
}
}
return true
}
func nodeListString(n []*node) string {
b := new(bytes.Buffer)
e := text.NewEncoder(b)
b.WriteByte('[')
for i, nn := range n {
if i > 0 {
b.WriteByte(' ')
}
e.Encode(0xe682ab4cf923a417, nn.Struct)
}
b.WriteByte(']')
return b.String()
}

View File

@@ -0,0 +1,194 @@
package main
import (
"fmt"
"strconv"
"strings"
"unicode"
"zombiezen.com/go/capnproto2"
)
type staticData struct {
name string
buf []byte
}
func (sd *staticData) init(fileID uint64) {
sd.name = fmt.Sprintf("x_%x", fileID)
sd.buf = make([]byte, 0, 4096)
}
func (sd *staticData) copyData(obj capnp.Ptr) (staticDataRef, error) {
m, _, err := capnp.NewMessage(capnp.SingleSegment(nil))
if err != nil {
return staticDataRef{}, err
}
err = m.SetRootPtr(obj)
if err != nil {
return staticDataRef{}, err
}
data, err := m.Marshal()
if err != nil {
return staticDataRef{}, err
}
ref := staticDataRef{data: sd}
ref.Start = len(sd.buf)
sd.buf = append(sd.buf, data...)
ref.End = len(sd.buf)
return ref, nil
}
type staticDataRef struct {
data *staticData
Start, End int
}
func (ref staticDataRef) IsValid() bool {
return ref.Start < ref.End
}
func (ref staticDataRef) String() string {
return fmt.Sprintf("%s[%d:%d]", ref.data.name, ref.Start, ref.End)
}
type imports struct {
specs []importSpec
used map[string]bool // keyed on import path
}
var capnpImportSpec = importSpec{path: capnpImport, name: "capnp"}
func (i *imports) init() {
i.specs = nil
i.used = make(map[string]bool)
i.reserve(capnpImportSpec)
i.reserve(importSpec{path: schemasImport, name: "schemas"})
i.reserve(importSpec{path: serverImport, name: "server"})
i.reserve(importSpec{path: textImport, name: "text"})
i.reserve(importSpec{path: contextImport, name: "context"})
i.reserve(importSpec{path: "math", name: "math"})
i.reserve(importSpec{path: "strconv", name: "strconv"})
}
func (i *imports) Capnp() string {
return i.add(importSpec{path: capnpImport, name: "capnp"})
}
func (i *imports) Schemas() string {
return i.add(importSpec{path: schemasImport, name: "schemas"})
}
func (i *imports) Server() string {
return i.add(importSpec{path: serverImport, name: "server"})
}
func (i *imports) Text() string {
return i.add(importSpec{path: textImport, name: "text"})
}
func (i *imports) Context() string {
return i.add(importSpec{path: contextImport, name: "context"})
}
func (i *imports) Math() string {
return i.add(importSpec{path: "math", name: "math"})
}
func (i *imports) Strconv() string {
return i.add(importSpec{path: "strconv", name: "strconv"})
}
func (i *imports) usedImports() []importSpec {
specs := make([]importSpec, 0, len(i.specs))
for _, s := range i.specs {
if i.used[s.path] {
specs = append(specs, s)
}
}
return specs
}
func (i *imports) byPath(path string) (spec importSpec, ok bool) {
for _, spec = range i.specs {
if spec.path == path {
return spec, true
}
}
return importSpec{}, false
}
func (i *imports) byName(name string) (spec importSpec, ok bool) {
for _, spec = range i.specs {
if spec.name == name {
return spec, true
}
}
return importSpec{}, false
}
func (i *imports) add(spec importSpec) (name string) {
name = i.reserve(spec)
i.used[spec.path] = true
return name
}
// reserve adds an import spec without marking it as used.
func (i *imports) reserve(spec importSpec) (name string) {
if ispec, ok := i.byPath(spec.path); ok {
return ispec.name
}
if spec.name == "" {
spec.name = pkgFromImport(spec.path)
}
if _, found := i.byName(spec.name); found {
for base, n := spec.name, uint64(2); ; n++ {
spec.name = base + strconv.FormatUint(n, 10)
if _, found = i.byName(spec.name); !found {
break
}
}
}
i.specs = append(i.specs, spec)
return spec.name
}
func pkgFromImport(path string) string {
if i := strings.LastIndex(path, "/"); i != -1 {
path = path[i+1:]
}
p := []rune(path)
n := 0
for _, r := range p {
if isIdent(r) {
p[n] = r
n++
}
}
if n == 0 || !isLower(p[0]) {
return "pkg" + string(p[:n])
}
return string(p[:n])
}
func isLower(r rune) bool {
return 'a' <= r && r <= 'z' || r == '_'
}
func isIdent(r rune) bool {
return isLower(r) || 'A' <= r && r <= 'Z' || r >= 0x80 && unicode.IsLetter(r)
}
type importSpec struct {
path string
name string
}
func (spec importSpec) String() string {
if spec.name == "" {
return strconv.Quote(spec.path)
}
return spec.name + " " + strconv.Quote(spec.path)
}

336
vendor/zombiezen.com/go/capnproto2/capnpc-go/nodes.go generated vendored Normal file
View File

@@ -0,0 +1,336 @@
package main
import (
"errors"
"fmt"
"strings"
"zombiezen.com/go/capnproto2"
"zombiezen.com/go/capnproto2/internal/schema"
)
type node struct {
schema.Node
pkg string
imp string
nodes []*node // only for file nodes
Name string
}
func (n *node) codeOrderFields() []field {
fields, _ := n.StructNode().Fields()
numFields := fields.Len()
mbrs := make([]field, numFields)
for i := 0; i < numFields; i++ {
f := fields.At(i)
fann, _ := f.Annotations()
fname, _ := f.Name()
fname = parseAnnotations(fann).Rename(fname)
mbrs[f.CodeOrder()] = field{Field: f, Name: fname}
}
return mbrs
}
// DiscriminantOffset returns the byte offset of the struct union discriminant.
func (n *node) DiscriminantOffset() (uint32, error) {
if n == nil {
return 0, errors.New("discriminant offset called on nil node")
}
if n.Which() != schema.Node_Which_structNode {
return 0, fmt.Errorf("discriminant offset called on %v node", n.Which())
}
return n.StructNode().DiscriminantOffset() * 2, nil
}
func (n *node) shortDisplayName() string {
dn, _ := n.DisplayName()
return dn[n.DisplayNamePrefixLength():]
}
// String returns the node's display name.
func (n *node) String() string {
return displayName(n)
}
func displayName(n interface {
DisplayName() (string, error)
}) string {
dn, _ := n.DisplayName()
return dn
}
type field struct {
schema.Field
Name string
}
// HasDiscriminant reports whether the field is in a union.
func (f field) HasDiscriminant() bool {
return f.DiscriminantValue() != schema.Field_noDiscriminant
}
type enumval struct {
schema.Enumerant
Name string
Val int
Tag string
parent *node
}
func makeEnumval(enum *node, i int, e schema.Enumerant) enumval {
eann, _ := e.Annotations()
ann := parseAnnotations(eann)
name, _ := e.Name()
name = ann.Rename(name)
t := ann.Tag(name)
return enumval{e, name, i, t, enum}
}
func (e *enumval) FullName() string {
return e.parent.Name + "_" + e.Name
}
type interfaceMethod struct {
schema.Method
Interface *node
ID int
Name string
OriginalName string
Params *node
Results *node
}
func methodSet(methods []interfaceMethod, n *node, nodes nodeMap) ([]interfaceMethod, error) {
ms, _ := n.Interface().Methods()
for i := 0; i < ms.Len(); i++ {
m := ms.At(i)
mname, _ := m.Name()
mann, _ := m.Annotations()
pn, err := nodes.mustFind(m.ParamStructType())
if err != nil {
return methods, fmt.Errorf("could not find param type for %s.%s", n.shortDisplayName(), mname)
}
rn, err := nodes.mustFind(m.ResultStructType())
if err != nil {
return methods, fmt.Errorf("could not find result type for %s.%s", n.shortDisplayName(), mname)
}
methods = append(methods, interfaceMethod{
Method: m,
Interface: n,
ID: i,
OriginalName: mname,
Name: parseAnnotations(mann).Rename(mname),
Params: pn,
Results: rn,
})
}
// TODO(light): sort added methods by code order
supers, _ := n.Interface().Superclasses()
for i := 0; i < supers.Len(); i++ {
s := supers.At(i)
sn, err := nodes.mustFind(s.Id())
if err != nil {
return methods, fmt.Errorf("could not find superclass %#x of %s", s.Id(), n)
}
methods, err = methodSet(methods, sn, nodes)
if err != nil {
return methods, err
}
}
return methods, nil
}
// Tag types
const (
defaultTag = iota
noTag
customTag
)
type annotations struct {
Doc string
Package string
Import string
TagType int
CustomTag string
Name string
}
func parseAnnotations(list schema.Annotation_List) *annotations {
ann := new(annotations)
for i, n := 0, list.Len(); i < n; i++ {
a := list.At(i)
val, _ := a.Value()
text, _ := val.Text()
switch a.Id() {
case capnp.Doc:
ann.Doc = text
case capnp.Package:
ann.Package = text
case capnp.Import:
ann.Import = text
case capnp.Tag:
ann.TagType = customTag
ann.CustomTag = text
case capnp.Notag:
ann.TagType = noTag
case capnp.Name:
ann.Name = text
}
}
return ann
}
// Tag returns the string value that an enumerant value called name should have.
// An empty string indicates that this enumerant value has no tag.
func (ann *annotations) Tag(name string) string {
switch ann.TagType {
case noTag:
return ""
case customTag:
return ann.CustomTag
case defaultTag:
fallthrough
default:
return name
}
}
// Rename returns the overridden name from the annotations or the given name
// if no annotation was found.
func (ann *annotations) Rename(given string) string {
if ann.Name == "" {
return given
}
return ann.Name
}
type nodeMap map[uint64]*node
func buildNodeMap(req schema.CodeGeneratorRequest) (nodeMap, error) {
rnodes, err := req.Nodes()
if err != nil {
return nil, err
}
nodes := make(nodeMap, rnodes.Len())
var allfiles []*node
for i := 0; i < rnodes.Len(); i++ {
ni := rnodes.At(i)
n := &node{Node: ni}
nodes[n.Id()] = n
if n.Which() == schema.Node_Which_file {
allfiles = append(allfiles, n)
}
}
for _, f := range allfiles {
fann, err := f.Annotations()
if err != nil {
return nil, fmt.Errorf("reading annotations for %v: %v", f, err)
}
ann := parseAnnotations(fann)
f.pkg = ann.Package
f.imp = ann.Import
nnodes, _ := f.NestedNodes()
for i := 0; i < nnodes.Len(); i++ {
nn := nnodes.At(i)
if ni := nodes[nn.Id()]; ni != nil {
nname, _ := nn.Name()
if err := resolveName(nodes, ni, "", nname, f); err != nil {
return nil, err
}
}
}
}
return nodes, nil
}
// resolveName is called as part of building up a node map to populate the name field of n.
func resolveName(nodes nodeMap, n *node, base, name string, file *node) error {
na, err := n.Annotations()
if err != nil {
return fmt.Errorf("reading annotations for %s: %v", n, err)
}
name = parseAnnotations(na).Rename(name)
if base == "" {
n.Name = strings.Title(name)
} else {
n.Name = base + "_" + name
}
n.pkg = file.pkg
n.imp = file.imp
file.nodes = append(file.nodes, n)
nnodes, err := n.NestedNodes()
if err != nil {
return fmt.Errorf("listing nested nodes for %s: %v", n, err)
}
for i := 0; i < nnodes.Len(); i++ {
nn := nnodes.At(i)
ni := nodes[nn.Id()]
if ni == nil {
continue
}
nname, err := nn.Name()
if err != nil {
return fmt.Errorf("reading name of nested node %d in %s: %v", i+1, n, err)
}
if err := resolveName(nodes, ni, n.Name, nname, file); err != nil {
return err
}
}
switch n.Which() {
case schema.Node_Which_structNode:
fields, _ := n.StructNode().Fields()
for i := 0; i < fields.Len(); i++ {
f := fields.At(i)
if f.Which() != schema.Field_Which_group {
continue
}
fa, _ := f.Annotations()
fname, _ := f.Name()
grp := nodes[f.Group().TypeId()]
if grp == nil {
return fmt.Errorf("could not find type information for group %s in %s", fname, n)
}
fname = parseAnnotations(fa).Rename(fname)
if err := resolveName(nodes, grp, n.Name, fname, file); err != nil {
return err
}
}
case schema.Node_Which_interface:
m, _ := n.Interface().Methods()
methodResolve := func(id uint64, mname string, base string, name string) error {
x := nodes[id]
if x == nil {
return fmt.Errorf("could not find type %#x for %s.%s", id, n, mname)
}
if x.ScopeId() != 0 {
return nil
}
return resolveName(nodes, x, base, name, file)
}
for i := 0; i < m.Len(); i++ {
mm := m.At(i)
mname, _ := mm.Name()
mann, _ := mm.Annotations()
base := n.Name + "_" + parseAnnotations(mann).Rename(mname)
if err := methodResolve(mm.ParamStructType(), mname, base, "Params"); err != nil {
return err
}
if err := methodResolve(mm.ResultStructType(), mname, base, "Results"); err != nil {
return err
}
}
}
return nil
}
func (nm nodeMap) mustFind(id uint64) (*node, error) {
n := nm[id]
if n == nil {
return nil, fmt.Errorf("could not find node %#x in schema", id)
}
return n, nil
}

View File

@@ -0,0 +1,236 @@
package main
import (
"bytes"
"fmt"
)
type annotationParams struct {
G *generator
Node *node
}
type constantsParams struct {
G *generator
Consts []*node
Vars []*node
}
type enumParams struct {
G *generator
Node *node
Annotations *annotations
EnumValues []enumval
}
type structTypesParams struct {
G *generator
Node *node
Annotations *annotations
BaseNode *node
}
func (p structTypesParams) IsBase() bool {
return p.Node == p.BaseNode
}
type baseStructFuncsParams struct {
G *generator
Node *node
StringMethod bool
}
type structFuncsParams struct {
G *generator
Node *node
}
type structGroupParams struct {
G *generator
Node *node
Group *node
Field field
}
type structFieldParams struct {
G *generator
Node *node
Field field
Annotations *annotations
FieldType string
}
type (
structFloatFieldParams structUintFieldParams
structInterfaceFieldParams structFieldParams
structVoidFieldParams structFieldParams
structListFieldParams structObjectFieldParams
structPointerFieldParams structObjectFieldParams
structStructFieldParams structObjectFieldParams
)
type structBoolFieldParams struct {
structFieldParams
Default bool
}
type structUintFieldParams struct {
structFieldParams
Bits uint
Default uint64
}
func (p structUintFieldParams) Offset() uint32 {
return p.Field.Slot().Offset() * uint32(p.Bits/8)
}
func (p structFloatFieldParams) Offset() uint32 {
return structUintFieldParams(p).Offset()
}
type structIntFieldParams struct {
structUintFieldParams
EnumName string
}
func (p structIntFieldParams) ReturnType() string {
if p.EnumName != "" {
return p.EnumName
}
return fmt.Sprintf("int%d", p.Bits)
}
type structTextFieldParams struct {
structFieldParams
Default string
}
type structDataFieldParams struct {
structFieldParams
Default []byte
}
type structObjectFieldParams struct {
structFieldParams
TypeNode *node
Default staticDataRef
}
type structListParams struct {
G *generator
Node *node
StringMethod bool
}
type structEnumsParams struct {
G *generator
Node *node
Fields []field
EnumString enumString
}
type promiseParams struct {
G *generator
Node *node
Fields []field
}
type promiseGroupParams struct {
G *generator
Node *node
Field field
Group *node
}
type promiseFieldStructParams struct {
G *generator
Node *node
Field field
Struct *node
Default staticDataRef
}
type promiseFieldAnyPointerParams struct {
G *generator
Node *node
Field field
}
type promiseFieldInterfaceParams struct {
G *generator
Node *node
Field field
Interface *node
}
type interfaceClientParams struct {
G *generator
Node *node
Annotations *annotations
Methods []interfaceMethod
}
type interfaceServerParams struct {
G *generator
Node *node
Annotations *annotations
Methods []interfaceMethod
}
type structValueParams struct {
G *generator
Node *node
Typ *node
Value staticDataRef
}
type pointerValueParams struct {
G *generator
Value staticDataRef
}
type listValueParams struct {
G *generator
Typ string
Value staticDataRef
}
type schemaVarParams struct {
G *generator
FileID uint64
NodeIDs []uint64
schema []byte
}
func (p schemaVarParams) SchemaLiteral() string {
const width = 16
var out bytes.Buffer
out.WriteByte('"')
for i, b := range p.schema {
if i > 0 && i%width == 0 {
out.WriteString("\" +\n\t\"")
}
switch {
case b < ' ' || b > '~':
// unprintable
out.WriteString("\\x")
out.WriteByte(hexdigit(b >> 4))
out.WriteByte(hexdigit(b & 0xf))
case b == '"':
out.WriteString("\\\"")
case b == '\\':
out.WriteString("\\\\")
default:
out.WriteByte(b)
}
}
out.WriteByte('"')
return out.String()
}
func hexdigit(b byte) byte {
if b < 10 {
return b + '0'
}
return (b - 10) + 'a'
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
{{if .Field.HasDiscriminant -}}
if s.Struct.Uint16({{.Node.DiscriminantOffset}}) != {{.Field.DiscriminantValue}} {
panic({{printf "Which() != %s" .Field.Name | printf "%q"}})
}
{{end -}}

View File

@@ -0,0 +1,9 @@
func (s {{.Node.Name}}) Has{{.Field.Name|title}}() bool {
{{if .Field.HasDiscriminant -}}
if s.Struct.Uint16({{.Node.DiscriminantOffset}}) != {{.Field.DiscriminantValue}} {
return false
}
{{end -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
return p.IsValid() || err != nil
}

View File

@@ -0,0 +1,4 @@
InterfaceID: {{.Interface.Id|printf "%#x"}},
MethodID: {{.ID}},
InterfaceName: {{.Interface.DisplayName|printf "%q"}},
MethodName: {{.OriginalName|printf "%q"}},

View File

@@ -0,0 +1,3 @@
{{if .Field.HasDiscriminant -}}
s.Struct.SetUint16({{.Node.DiscriminantOffset}}, {{.Field.DiscriminantValue}})
{{end -}}

View File

@@ -0,0 +1,2 @@
// {{.Name}}_TypeID is the unique identifier for the type {{.Name}}.
const {{.Name}}_TypeID = {{.Id|printf "%#x"}}

View File

@@ -0,0 +1 @@
const {{.Node.Name}} = uint64({{.Node.Id|printf "%#x"}})

View File

@@ -0,0 +1,23 @@
{{ template "_typeid" .Node }}
func New{{.Node.Name}}(s *{{.G.Capnp}}.Segment) ({{.Node.Name}}, error) {
st, err := {{$.G.Capnp}}.NewStruct(s, {{.G.ObjectSize .Node}})
return {{.Node.Name}}{st}, err
}
func NewRoot{{.Node.Name}}(s *{{.G.Capnp}}.Segment) ({{.Node.Name}}, error) {
st, err := {{.G.Capnp}}.NewRootStruct(s, {{.G.ObjectSize .Node}})
return {{.Node.Name}}{st}, err
}
func ReadRoot{{.Node.Name}}(msg *{{.G.Capnp}}.Message) ({{.Node.Name}}, error) {
root, err := msg.RootPtr()
return {{.Node.Name}}{root.Struct()}, err
}
{{if .StringMethod}}
func (s {{.Node.Name}}) String() string {
str, _ := {{.G.Imports.Text}}.Marshal({{.Node.Id|printf "%#x"}}, s.Struct)
return str
}
{{end}}

View File

@@ -0,0 +1,14 @@
{{with .Consts -}}
// Constants defined in {{$.G.Basename}}.
const (
{{range .}} {{.Name}} = {{$.G.Value . .Const.Type .Const.Value}}
{{end}}
)
{{end}}
{{with .Vars -}}
// Constants defined in {{$.G.Basename}}.
var (
{{range .}} {{.Name}} = {{$.G.Value . .Const.Type .Const.Value}}
{{end}}
)
{{end}}

View File

@@ -0,0 +1,55 @@
{{with .Annotations.Doc -}}
// {{.}}
{{end -}}
type {{.Node.Name}} uint16
{{ template "_typeid" .Node }}
{{with .EnumValues -}}
// Values of {{$.Node.Name}}.
const (
{{range . -}}
{{.FullName}} {{$.Node.Name}} = {{.Val}}
{{end}}
)
// String returns the enum's constant name.
func (c {{$.Node.Name}}) String() string {
switch c {
{{range . -}}
{{if .Tag}}case {{.FullName}}: return {{printf "%q" .Tag}}
{{end}}
{{- end}}
default: return ""
}
}
// {{$.Node.Name}}FromString returns the enum value with a name,
// or the zero value if there's no such value.
func {{$.Node.Name}}FromString(c string) {{$.Node.Name}} {
switch c {
{{range . -}}
{{if .Tag}}case {{printf "%q" .Tag}}: return {{.FullName}}
{{end}}
{{- end}}
default: return 0
}
}
{{end}}
type {{.Node.Name}}_List struct { {{$.G.Capnp}}.List }
func New{{.Node.Name}}_List(s *{{$.G.Capnp}}.Segment, sz int32) ({{.Node.Name}}_List, error) {
l, err := {{.G.Capnp}}.NewUInt16List(s, sz)
return {{.Node.Name}}_List{l.List}, err
}
func (l {{.Node.Name}}_List) At(i int) {{.Node.Name}} {
ul := {{.G.Capnp}}.UInt16List{List: l.List}
return {{.Node.Name}}(ul.At(i))
}
func (l {{.Node.Name}}_List) Set(i int, v {{.Node.Name}}) {
ul := {{.G.Capnp}}.UInt16List{List: l.List}
ul.Set(i, uint16(v))
}

View File

@@ -0,0 +1,26 @@
{{with .Annotations.Doc -}}
// {{.}}
{{end -}}
type {{.Node.Name}} struct { Client {{.G.Capnp}}.Client }
{{ template "_typeid" .Node }}
{{range .Methods -}}
func (c {{$.Node.Name}}) {{.Name|title}}(ctx {{$.G.Imports.Context}}.Context, params func({{$.G.RemoteNodeName .Params $.Node}}) error, opts ...{{$.G.Capnp}}.CallOption) {{$.G.RemoteNodeName .Results $.Node}}_Promise {
if c.Client == nil {
return {{$.G.RemoteNodeName .Results $.Node}}_Promise{Pipeline: {{$.G.Capnp}}.NewPipeline({{$.G.Capnp}}.ErrorAnswer({{$.G.Capnp}}.ErrNullClient))}
}
call := &{{$.G.Capnp}}.Call{
Ctx: ctx,
Method: {{$.G.Capnp}}.Method{
{{template "_interfaceMethod" .}}
},
Options: {{$.G.Capnp}}.NewCallOptions(opts),
}
if params != nil {
call.ParamsSize = {{$.G.ObjectSize .Params}}
call.ParamsFunc = func(s {{$.G.Capnp}}.Struct) error { return params({{$.G.RemoteNodeName .Params $.Node}}{Struct: s}) }
}
return {{$.G.RemoteNodeName .Results $.Node}}_Promise{Pipeline: {{$.G.Capnp}}.NewPipeline(c.Client.Call(call))}
}
{{end}}

View File

@@ -0,0 +1,40 @@
type {{.Node.Name}}_Server interface {
{{range .Methods}}
{{.Name|title}}({{$.G.RemoteNodeName .Interface $.Node}}_{{.Name}}) error
{{end}}
}
func {{.Node.Name}}_ServerToClient(s {{.Node.Name}}_Server) {{.Node.Name}} {
c, _ := s.({{.G.Imports.Server}}.Closer)
return {{.Node.Name}}{Client: {{.G.Imports.Server}}.New({{.Node.Name}}_Methods(nil, s), c)}
}
func {{.Node.Name}}_Methods(methods []{{.G.Imports.Server}}.Method, s {{.Node.Name}}_Server) []{{.G.Imports.Server}}.Method {
if cap(methods) == 0 {
methods = make([]{{.G.Imports.Server}}.Method, 0, {{len .Methods}})
}
{{range .Methods}}
methods = append(methods, {{$.G.Imports.Server}}.Method{
Method: {{$.G.Capnp}}.Method{
{{template "_interfaceMethod" .}}
},
Impl: func(c {{$.G.Imports.Context}}.Context, opts {{$.G.Capnp}}.CallOptions, p, r {{$.G.Capnp}}.Struct) error {
call := {{$.G.RemoteNodeName .Interface $.Node}}_{{.Name}}{c, opts, {{$.G.RemoteNodeName .Params $.Node}}{Struct: p}, {{$.G.RemoteNodeName .Results $.Node}}{Struct: r} }
return s.{{.Name|title}}(call)
},
ResultsSize: {{$.G.ObjectSize .Results}},
})
{{end}}
return methods
}
{{range .Methods -}}
{{if eq .Interface.Id $.Node.Id}}
// {{$.Node.Name}}_{{.Name}} holds the arguments for a server call to {{$.Node.Name}}.{{.Name}}.
type {{$.Node.Name}}_{{.Name}} struct {
Ctx {{$.G.Imports.Context}}.Context
Options {{$.G.Capnp}}.CallOptions
Params {{$.G.RemoteNodeName .Params $.Node}}
Results {{$.G.RemoteNodeName .Results $.Node}}
}
{{end}}
{{- end}}

View File

@@ -0,0 +1,2 @@
{{.Typ}}{List: {{.G.Capnp}}.MustUnmarshalRootPtr({{.Value}}).List()}
{{- /* no EOL */ -}}

View File

@@ -0,0 +1,2 @@
{{.G.Capnp}}.MustUnmarshalRootPtr({{.Value}})
{{- /* no EOL */ -}}

View File

@@ -0,0 +1,8 @@
// {{.Node.Name}}_Promise is a wrapper for a {{.Node.Name}} promised by a client call.
type {{.Node.Name}}_Promise struct { *{{.G.Capnp}}.Pipeline }
func (p {{.Node.Name}}_Promise) Struct() ({{.Node.Name}}, error) {
s, err := p.Pipeline.Struct()
return {{.Node.Name}}{s}, err
}

View File

@@ -0,0 +1,4 @@
func (p {{.Node.Name}}_Promise) {{.Field.Name|title}}() *{{.G.Capnp}}.Pipeline {
return p.Pipeline.GetPipeline({{.Field.Slot.Offset}})
}

View File

@@ -0,0 +1,4 @@
func (p {{.Node.Name}}_Promise) {{.Field.Name|title}}() {{.G.RemoteNodeName .Interface .Node}} {
return {{.G.RemoteNodeName .Interface .Node}}{Client: p.Pipeline.GetPipeline({{.Field.Slot.Offset}}).Client()}
}

View File

@@ -0,0 +1,4 @@
func (p {{.Node.Name}}_Promise) {{.Field.Name|title}}() {{.G.RemoteNodeName .Struct .Node}}_Promise {
return {{.G.RemoteNodeName .Struct .Node}}_Promise{Pipeline: p.Pipeline.{{if .Default.IsValid}}GetPipelineDefault({{.Field.Slot.Offset}}, {{.Default}}){{else}}GetPipeline({{.Field.Slot.Offset}}){{end}} }
}

View File

@@ -0,0 +1 @@
func (p {{.Node.Name}}_Promise) {{.Field.Name|title}}() {{.Group.Name}}_Promise { return {{.Group.Name}}_Promise{p.Pipeline} }

View File

@@ -0,0 +1,8 @@
const schema_{{.FileID|printf "%x"}} = {{.SchemaLiteral}}
func init() {
{{.G.Imports.Schemas}}.Register(schema_{{.FileID|printf "%x"}},
{{- range .NodeIDs}}
{{.|printf "%#x"}},
{{- end}})
}

View File

@@ -0,0 +1,10 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() bool {
{{template "_checktag" . -}}
return {{if .Default}}!{{end}}s.Struct.Bit({{.Field.Slot.Offset}})
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v bool) {
{{template "_settag" . -}}
s.Struct.SetBit({{.Field.Slot.Offset}}, {{if .Default}}!{{end}}v)
}

View File

@@ -0,0 +1,22 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() ({{.FieldType}}, error) {
{{template "_checktag" . -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
{{with .Default -}}
return {{$.FieldType}}(p.DataDefault({{printf "%#v" .}})), err
{{- else -}}
return {{.FieldType}}(p.Data()), err
{{- end}}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.FieldType}}) error {
{{template "_settag" . -}}
{{if .Default -}}
if v == nil {
v = []byte{}
}
{{end -}}
return s.Struct.SetData({{.Field.Slot.Offset}}, v)
}

View File

@@ -0,0 +1,17 @@
type {{.Node.Name}}_Which uint16
const (
{{range .Fields}} {{$.Node.Name}}_Which_{{.Name}} {{$.Node.Name}}_Which = {{.DiscriminantValue}}
{{end}}
)
func (w {{.Node.Name}}_Which) String() string {
const s = {{.EnumString.ValueString|printf "%q"}}
switch w {
{{range $i, $f := .Fields}}case {{$.Node.Name}}_Which_{{.Name}}:
return s{{$.EnumString.SliceFor $i}}
{{end}}
}
return "{{.Node.Name}}_Which(" + {{.G.Imports.Strconv}}.FormatUint(uint64(w), 10) + ")"
}

View File

@@ -0,0 +1,10 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() float{{.Bits}} {
{{template "_checktag" . -}}
return {{.G.Imports.Math}}.Float{{.Bits}}frombits(s.Struct.Uint{{.Bits}}({{.Offset}}){{with .Default}} ^ {{printf "%#x" .}}{{end}})
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v float{{.Bits}}) {
{{template "_settag" . -}}
s.Struct.SetUint{{.Bits}}({{.Offset}}, {{.G.Imports.Math}}.Float{{.Bits}}bits(v){{with .Default}}^{{printf "%#x" .}}{{end}})
}

View File

@@ -0,0 +1,5 @@
{{if gt .Node.StructNode.DiscriminantCount 0}}
func (s {{.Node.Name}}) Which() {{.Node.Name}}_Which {
return {{.Node.Name}}_Which(s.Struct.Uint16({{.Node.DiscriminantOffset}}))
}
{{end -}}

View File

@@ -0,0 +1,4 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() {{.Group.Name}} { return {{.Group.Name}}(s) }
{{if .Field.HasDiscriminant}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}() { {{template "_settag" .}} }
{{end}}

View File

@@ -0,0 +1,10 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() {{.ReturnType}} {
{{template "_checktag" . -}}
return {{.ReturnType}}(s.Struct.Uint{{.Bits}}({{.Offset}}){{with .Default}} ^ {{.}}{{end}})
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.ReturnType}}) {
{{template "_settag" . -}}
s.Struct.SetUint{{.Bits}}({{.Offset}}, uint{{.Bits}}(v){{with .Default}}^{{.}}{{end}})
}

View File

@@ -0,0 +1,18 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() {{.FieldType}} {
{{template "_checktag" . -}}
p, _ := s.Struct.Ptr({{.Field.Slot.Offset}})
return {{.FieldType}}{Client: p.Interface().Client()}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.FieldType}}) error {
{{template "_settag" . -}}
if v.Client == nil {
return s.Struct.SetPtr({{.Field.Slot.Offset}}, capnp.Ptr{})
}
seg := s.Segment()
in := {{.G.Capnp}}.NewInterface(seg, seg.Message().AddCap(v.Client))
return s.Struct.SetPtr({{.Field.Slot.Offset}}, in.ToPtr())
}

View File

@@ -0,0 +1,19 @@
// {{.Node.Name}}_List is a list of {{.Node.Name}}.
type {{.Node.Name}}_List struct{ {{.G.Capnp}}.List }
// New{{.Node.Name}} creates a new list of {{.Node.Name}}.
func New{{.Node.Name}}_List(s *{{.G.Capnp}}.Segment, sz int32) ({{.Node.Name}}_List, error) {
l, err := {{.G.Capnp}}.NewCompositeList(s, {{.G.ObjectSize .Node}}, sz)
return {{.Node.Name}}_List{l}, err
}
func (s {{.Node.Name}}_List) At(i int) {{.Node.Name}} { return {{.Node.Name}}{ s.List.Struct(i) } }
func (s {{.Node.Name}}_List) Set(i int, v {{.Node.Name}}) error { return s.List.SetStruct(i, v.Struct) }
{{if .StringMethod}}
func (s {{.Node.Name}}_List) String() string {
str, _ := {{.G.Imports.Text}}.MarshalList({{.Node.Id|printf "%#x"}}, s.List)
return str
}
{{end}}

View File

@@ -0,0 +1,33 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() ({{.FieldType}}, error) {
{{template "_checktag" . -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
{{if .Default.IsValid -}}
if err != nil {
return {{.FieldType}}{}, err
}
l, err := p.ListDefault({{.Default}})
return {{.FieldType}}{List: l}, err
{{- else -}}
return {{.FieldType}}{List: p.List()}, err
{{- end}}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.FieldType}}) error {
{{template "_settag" . -}}
return s.Struct.SetPtr({{.Field.Slot.Offset}}, v.List.ToPtr())
}
// New{{.Field.Name|title}} sets the {{.Field.Name}} field to a newly
// allocated {{.FieldType}}, preferring placement in s's segment.
func (s {{.Node.Name}}) New{{.Field.Name|title}}(n int32) ({{.FieldType}}, error) {
{{template "_settag" . -}}
l, err := {{.G.RemoteTypeNew .Field.Slot.Type .Node}}(s.Struct.Segment(), n)
if err != nil {
return {{.FieldType}}{}, err
}
err = s.Struct.SetPtr({{.Field.Slot.Offset}}, l.List.ToPtr())
return l, err
}

View File

@@ -0,0 +1,37 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() ({{.G.Capnp}}.Pointer, error) {
{{template "_checktag" . -}}
{{if .Default.IsValid -}}
p, err := s.Struct.Pointer({{.Field.Slot.Offset}})
if err != nil {
return nil, err
}
return {{.G.Capnp}}.PointerDefault(p, {{.Default}})
{{- else -}}
return s.Struct.Pointer({{.Field.Slot.Offset}})
{{- end}}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) {{.Field.Name|title}}Ptr() ({{.G.Capnp}}.Ptr, error) {
{{if .Default.IsValid -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
if err != nil {
return nil, err
}
return p.Default({{.Default}})
{{- else -}}
return s.Struct.Ptr({{.Field.Slot.Offset}})
{{- end}}
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.G.Capnp}}.Pointer) error {
{{template "_settag" . -}}
return s.Struct.SetPointer({{.Field.Slot.Offset}}, v)
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}Ptr(v {{.G.Capnp}}.Ptr) error {
{{template "_settag" . -}}
return s.Struct.SetPtr({{.Field.Slot.Offset}}, v)
}

View File

@@ -0,0 +1,33 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() ({{.FieldType}}, error) {
{{template "_checktag" . -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
{{if .Default.IsValid -}}
if err != nil {
return {{.FieldType}}{}, err
}
ss, err := p.StructDefault({{.Default}})
return {{.FieldType}}{Struct: ss}, err
{{- else -}}
return {{.FieldType}}{Struct: p.Struct()}, err
{{- end}}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v {{.FieldType}}) error {
{{template "_settag" . -}}
return s.Struct.SetPtr({{.Field.Slot.Offset}}, v.Struct.ToPtr())
}
// New{{.Field.Name|title}} sets the {{.Field.Name}} field to a newly
// allocated {{.FieldType}} struct, preferring placement in s's segment.
func (s {{.Node.Name}}) New{{.Field.Name|title}}() ({{.FieldType}}, error) {
{{template "_settag" . -}}
ss, err := {{.G.RemoteNodeNew .TypeNode .Node}}(s.Struct.Segment())
if err != nil {
return {{.FieldType}}{}, err
}
err = s.Struct.SetPtr({{.Field.Slot.Offset}}, ss.Struct.ToPtr())
return ss, err
}

View File

@@ -0,0 +1,30 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() (string, error) {
{{template "_checktag" . -}}
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
{{with .Default -}}
return p.TextDefault({{printf "%q" .}}), err
{{- else -}}
return p.Text(), err
{{- end}}
}
{{template "_hasfield" .}}
func (s {{.Node.Name}}) {{.Field.Name|title}}Bytes() ([]byte, error) {
p, err := s.Struct.Ptr({{.Field.Slot.Offset}})
{{with .Default -}}
return p.TextBytesDefault({{printf "%q" .}}), err
{{- else -}}
return p.TextBytes(), err
{{- end}}
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v string) error {
{{template "_settag" . -}}
{{if .Default -}}
return s.Struct.SetNewText({{.Field.Slot.Offset}}, v)
{{- else -}}
return s.Struct.SetText({{.Field.Slot.Offset}}, v)
{{- end}}
}

View File

@@ -0,0 +1,8 @@
{{with .Annotations.Doc -}}
// {{.}}
{{end -}}
type {{.Node.Name}} {{if .IsBase -}}
struct{ {{.G.Capnp}}.Struct }
{{- else -}}
{{.BaseNode.Name}}
{{- end}}

View File

@@ -0,0 +1,10 @@
func (s {{.Node.Name}}) {{.Field.Name|title}}() uint{{.Bits}} {
{{template "_checktag" . -}}
return s.Struct.Uint{{.Bits}}({{.Offset}}){{with .Default}} ^ {{.}}{{end}}
}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}(v uint{{.Bits}}) {
{{template "_settag" . -}}
s.Struct.SetUint{{.Bits}}({{.Offset}}, v{{with .Default}}^{{.}}{{end}})
}

View File

@@ -0,0 +1,2 @@
{{.G.RemoteNodeName .Typ .Node}}{Struct: {{.G.Capnp}}.MustUnmarshalRootPtr({{.Value}}).Struct()}
{{- /* no EOL */ -}}

View File

@@ -0,0 +1,6 @@
{{if .Field.HasDiscriminant -}}
func (s {{.Node.Name}}) Set{{.Field.Name|title}}() {
{{template "_settag" .}}
}
{{end -}}

Binary file not shown.

View File

@@ -0,0 +1,13 @@
# Generate scopes.capnp.out with:
# capnp compile -o- scopes.capnp > scopes.capnp.out
# Must run inside this directory to preserve paths.
using Go = import "go.capnp";
@0xc260cb50ae622e10;
$Go.package("const");
$Go.import("zombiezen.com/go/capnproto2/capnpc-go/testdata/const");
const answer @0xda96e2255811b258 :Int64 = 42;
const blob @0xe0a385c7be1fea4d :Data = "\x01\x02\x03";

Binary file not shown.

View File

@@ -0,0 +1,15 @@
# Generate go.capnp.out with:
# capnp compile -o- go.capnp > go.capnp.out
# Must run inside this directory to preserve paths.
@0xd12a1c51fedd6c88;
annotation package(file) :Text;
annotation import(file) :Text;
annotation doc(struct, field, enum) :Text;
annotation tag(enumerant) :Text;
annotation notag(enumerant) :Void;
annotation customtype(field) :Text;
annotation name(struct, field, union, enum, enumerant, interface, method, param, annotation, const, group) :Text;
$package("capnp");

Binary file not shown.

View File

@@ -0,0 +1,11 @@
using Go = import "go.capnp";
@0x83c2b5818e83ab19;
$Go.package("template_fix");
$Go.import("zombiezen.com/go/capnproto2/capnpc-go/testdata/group");
struct SomeMisguidedStruct {
someGroup :group {
someGroupField @0 :UInt64;
}
}

Binary file not shown.

View File

@@ -0,0 +1,11 @@
# File to be imported from scopes.capnp.
using Go = import "go.capnp";
@0x9c339b0568fe60ba;
$Go.package("otherscopes");
$Go.import("zombiezen.com/go/capnproto2/capnpc-go/testdata/otherscopes");
struct Foo @0xd127518fcfe6191d {
}

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# Generate scopes.capnp.out with:
# capnp compile -o- scopes.capnp > scopes.capnp.out
# Must run inside this directory to preserve paths.
using Go = import "go.capnp";
using Other = import "otherscopes.capnp";
@0xd68755941d99d05e;
$Go.package("scopes");
$Go.import("zombiezen.com/go/capnproto2/capnpc-go/testdata/scopes");
struct Foo @0xc8d7b3b4e07f8bd9 {
}
const fooVar @0x84efedc75e99768d :Foo = ();
const otherFooVar @0x836faf1834d91729 :Other.Foo = ();
const fooListVar @0xcda2680ec5c921e0 :List(Foo) = [];
const otherFooListVar @0x83e7e1b3cd1be338 :List(Other.Foo) = [];
const intList @0xacf3d9917d0bb0f0 :List(Int32) = [];

Binary file not shown.

View File

@@ -0,0 +1,173 @@
# Sandstorm - Personal Cloud Sandbox
# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Derived from sandstorm at 08fafe55995edfe188777eb00b5a2d1826032c59.
# Using Go annotations.
@0xecd50d792c3d9992;
using Go = import "go.capnp";
$Go.package("util");
$Go.import("zombiezen.com/go/capnproto2/capnpc-go/testdata/util");
using DateInNs = Int64;
using DurationInNs = UInt64;
struct KeyValue {
key @0 :Text;
value @1 :Text;
}
struct LocalizedText {
# Text intended to be displayed to a user. May be localized to multiple languages.
#
# TODO(soon): Maybe instead of packing all translations in here, we should have a message code
# and parameter substitutions, with the (message code, locale) -> text map stored elsewhere?
defaultText @0 :Text;
# What to display if no localization matching the user's preferences is available.
localizations @1 :List(Localization);
# Localized versions of the text.
struct Localization {
locale @0 :Text; # IETF BCP 47 locale, e.g. "en" or "en-US".
text @1 :Text; # Localized text.
}
}
interface Handle {
# Arbitrary handle to some resource provided by the platform. May or may not be persistent,
# depending on the use case.
#
# To "drop" a handle means to discard any references. The purpose of a handle is to detect when
# it has been dropped and to free the underlying resource and cancel any ongoing operation at
# that time.
#
# A handle can be persistent. Once you have called `save()` on it to obtain a SturdyRef, dropping
# the live reference will not cancel the operation. You must drop all live references *and*
# explicitly drop any SturdyRef. Every interface which supports restoring SturdyRefs also
# has a corresponding `drop()` method for this purpose.
#
# Unfortunately, there is no way to ensure that a SturdyRef will eventually be deleted. A grain
# could, for example, call `save()` and then simply fail to store the SturdyRef anywhere, causing
# it to be "leaked" until such a time as the grain itself is destroyed. Or worse, a whole server
# could be destroyed in a fire, leaking all SturdyRefs stored therein forever. Apps implementing
# persistent handles must be designed to account for this, probably by giving the owning user
# a way to inspect incoming references and remove them manually. Sandstorm automatically provides
# such an interface for all apps it hosts.
}
interface ByteStream {
# Represents a destination for a stream of bytes. The bytes are ordered, but boundaries between
# messages are not semantically important.
#
# Streams are push-oriented (traditionally, "output streams") rather than pull-oriented ("input
# streams") because this most easily allows multiple packets to be in-flight at once while
# allowing flow control at either end. If we tried to design a pull-oriented stream, it would
# suffer from problems:
# * If we used a naive read() method that returns a simple data blob, you would need to make
# multiple simultaneous calls to deal with network latency. However, those calls could
# potentially return in the wrong order. Although you could restore order by keeping track of
# the order in which the calls were made, this would be a lot of work, and most callers would
# probably fail to do it.
# * We could instead have a read() method that returns a blob as well as a capability to read the
# next blob. You would then make multiple calls using pipelining. Even in this case, though,
# an unpredictable event loop could schedule a pipelined call's return before the parent call.
# Moreover, the interface would be awkward to use and implement. E.g. what happens if you call
# read() twice on the same capability?
write @0 (data :Data);
# Add bytes.
#
# It's safe to make overlapping calls to `write()`, since Cap'n Proto enforces E-Order and so
# the calls will be delivered in order. However, it is a good idea to limit how much data is
# in-flight at a time, so that it doesn't fill up buffers and block other traffic. On the other
# hand, having only one `write()` in flight at a time will not fully utilize the available
# bandwidth if the connection has any significant latency, so parallelizing a few `write()`s is
# a good idea.
#
# Similarly, the implementation of `ByteStream` can delay returning from `write()` as a way to
# hint to the caller that it should hold off on further writes.
done @1 ();
# Call after the last write to indicate that there is no more data. If the `ByteStream` is
# discarded without a call to `done()`, the callee must assume that an error occurred and that
# the data is incomplete.
#
# This will not return until all bytes are successfully written to their final destination.
# It will throw an exception if any error occurs, including if the total number of bytes written
# did not match `expectSize()`.
expectSize @2 (size :UInt64);
# Optionally called to let the receiver know exactly how much data will be written. This should
# normally be called before the first write(), but if called later, `size` indicates how many
# more bytes to expect _after_ the call. It is an error by the caller if more or fewer bytes are
# actually written before `done()`; this also implies that all calls to `expectSize()` must be
# consistent. The caller will ignore any exceptions thrown from this method, therefore it
# is not necessary for the callee to actually implement it.
}
interface Blob @0xe53527a75d90198f {
# Represents a large byte blob.
getSize @0 () -> (size :UInt64);
# Get the total size of the blob. May block if the blob is still being uploaded and the size is
# not yet known.
writeTo @1 (stream :ByteStream, startAtOffset :UInt64 = 0) -> (handle :Handle);
# Write the contents of the blob to `stream`.
getSlice @2 (offset :UInt64, size :UInt32) -> (data :Data);
# Read a slice of the blob starting at the given offset. `size` cannot be greater than Cap'n
# Proto's limit of 2^29-1, and reasonable servers will likely impose far lower limits. If the
# slice would cross past the end of the blob, it is truncated. Otherwise, `data` is always
# exactly `size` bytes (though the caller should check for security purposes).
#
# One technique that makes a lot of sense is to start off by calling e.g. `getSlice(0, 65536)`.
# If the returned data is less than 65536 bytes then you know you got the whole blob, otherwise
# you may want to switch to `writeTo`.
}
interface Assignable(T) {
# An "assignable" -- a mutable memory cell. Supports subscribing to updates.
get @0 () -> (value :T, setter :Setter);
# The returned setter functions the same as you'd get from `asSetter()` except that it will
# become disconnected the next time the Assignable is set by someone else. Thus, you may use this
# to implement optimistic concurrency control.
asGetter @1 () -> (getter :Getter);
# Return a read-only capability for this assignable, co-hosted with the assignable itself for
# performance. If the assignable is persistent, the getter is as well.
asSetter @2 () -> (setter :Setter);
# Return a write-only capability for this assignable, co-hosted with the assignable itself for
# performance. If the assignable is persistent, the setter is as well.
interface Getter {
get @0 () -> (value :T);
subscribe @1 (setter :Setter) -> (handle :Handle);
# Subscribe to updates. Calls the given setter any time the assignable's value changes. Drop
# the returned handle to stop receiving updates. If `setter` is persistent, `handle` will also
# be persistent.
}
interface Setter {
set @0 (value :T) -> ();
}
}

Binary file not shown.