/
doc.go
130 lines (91 loc) · 3.76 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package codec implements an encoder for Go values. It relies on code generation
rather than reflection, so it is significantly faster than reflection-based
encoders like gob. It can also preserve sharing among pointers (but not other
forms of sharing, like sub-slices).
Encodings with maps are not deterministic, due to the non-deterministic order of
map iteration.
Generating Code
The package supports Go built-in types (int, string and so on) out of the box,
but for any other type you must generate code by calling GenerateFile. This can
be done with a small program in your project's directory:
// file generate.go
//+build ignore
package main
import (
"mypkg"
"github.com/jba/codec"
)
func main() {
err := codec.GenerateFile("types.gen.go", "mypkg", nil,
[]mypkg.Type1{}, &mypkg.Type2{})
if err != nil {
log.Fatal(err)
}
}
Code will be generated for each type listed and for all types they contain. So
this program will generate code for []mypkg.Type1, mypkg.Type1, *mypkg.Type2,
and mypkg.Type2.
The "//+build ignore" tag prevents the program from being compiled as part of
your package. Instead, invoke it directly with "go run". Use "go generate" to do
so if you like:
//go:generate go run generate.go
On subsequent runs, the generator reads the generated file to get the names and
order of all struct fields. It uses this information to generate correct code
when fields are moved or added. Make sure the old generated files remain
available to the generator, or changes to your structs may result in existing
encoded data being decoded incorrectly.
Encoding and Decoding
Create an Encoder by passing it an io.Writer:
var buf bytes.Buffer
e := codec.NewEncoder(&buf, nil)
Then use it to encode one or more values:
if err := e.Encode(x); err != nil { ... }
To decode, pass an io.Reader to NewDecoder, and call Decode:
f, err := os.Open(filename)
...
d := codec.NewDecoder(f, nil)
var value interface{}
err := d.Decode(&value)
...
Sharing and Cycles
By default, if two pointers point to the same value, that value will be
duplicated upon decoding. If there is a cycle, where a value directly or
indirectly points to itself, then the encoder will crash by exceeding available
stack space. This is the same behavior as encoding/gob and many other encoders.
Set EncodeOptions.TrackPointers to true to preserve pointer sharing and cycles,
at the cost of slower encoding.
Other forms of memory sharing are not preserved. For example, if two slices
refer to the same underlying array during encoding, they will refer to separate
arrays after decoding.
Struct Tags
Struct tags in the style of encoding/json are supported, under the name "codec".
You can easily generate code for structs designed for the encoding/json package
by changing the name to "json" in an option to GenerateFile.
An example:
type T struct {
A int `codec:"B"`
C int `codec:"-"`
}
Here, field A will use the name "B" and field C will be omitted. There is no
need for the omitempty option because the encoder always omits zero values.
Since the encoding uses numbers for fields instead of names, renaming a field
doesn't actually affect the encoding. It does matter if subsequent changes are
made to the struct, however. For example, say that originally T was
type T struct {
A int
}
but you rename the field to "B":
type T struct {
B int
}
The generator will treat "B" as a new field. Data encoded with "A" will not be
decoded into "B". So you should use a tag to express that it is a renaming:
type T struct {
B int `codec:"A"`
}
*/
package codec