зеркало из https://github.com/golang/pkgsite.git
85 строки
3.9 KiB
Go
85 строки
3.9 KiB
Go
// Copyright 2020 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 the general-purpose part of 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 also
|
|
preserves sharing among struct pointers (but not other forms of sharing, like
|
|
other pointer types or sub-slices). These features are sufficient for
|
|
encoding the structures of the go/ast package, which is its sole purpose.
|
|
|
|
# Encoding Scheme
|
|
|
|
Every encoded value begins with a single byte that describes what (if anything) follows.
|
|
A value's encoding contains enough information to skip over the value, since the
|
|
decoder must be able to do that if it encounters a struct field it doesn't know.
|
|
|
|
Most of the values of that initial byte can be devoted to small unsigned
|
|
integers. For example, the number 17 is represented by the single byte 17.
|
|
Only a few byte values have special meanings, whose descriptions follow.
|
|
|
|
The nil code indicates that the value is nil. We don't absolutely need this:
|
|
we could always represent the nil value for a type as something that couldn't
|
|
be mistaken for an encoded value of that type. For instance, we could use 0
|
|
for nil in the case of slices (which always begin with the nValues code), and
|
|
for pointers to numbers like *int, we could use something like "nBytes 0".
|
|
But it is simpler to have a reserved value for nil.
|
|
|
|
The nBytes code indicates that an unsigned integer N is encoded next,
|
|
followed by N bytes of data. This is used to represent strings and byte
|
|
slices, as well numbers bigger than can fit into the initial byte. For
|
|
example, the string "hi" is represented as:
|
|
|
|
nBytes 2 'h' 'i'
|
|
|
|
Unsigned integers that can't fit into the initial byte are encoded as byte
|
|
sequences of length 4 or 8, holding little-endian uint32 or uint64 values. We
|
|
use uint32s where possible to save space. For example, 255 is encoded as
|
|
|
|
nBytes 4 0 0 0 255
|
|
|
|
This representation is not as space-efficient as others, but improving its space
|
|
usage didn't seem worth the additional complexity.
|
|
|
|
Signed integers use gob's encoding.
|
|
|
|
Floats are encoded by converting them to uints using math.Float64bits.
|
|
|
|
The nValues code is for sequences of values whose size is known beforehand,
|
|
like a Go slice or array. The slice []string{"hi", "bye"} is encoded as
|
|
|
|
nValues 2 nBytes 2 'h' 'i' nBytes 3 'b' 'y' 'e'
|
|
|
|
The ref code is used to refer to an earlier encoded value. It is followed by
|
|
a uint denoting the index data of the value to use.
|
|
|
|
The start and end codes delimit a value whose length is unknown beforehand.
|
|
They are used for structs.
|
|
|
|
A struct is encoded as a sequence of fields between a start code and an end code.
|
|
Each exported field is encoded as an integer field number followed by the field's value.
|
|
Fields with zero values are omitted.
|
|
|
|
The field number is initially the position of the field in the struct declaration. This
|
|
initial ordering is preserved even if fields are added or removed; new fields are
|
|
numbered after the initial ones. This is accomplished by preserving the field ordering
|
|
in a comment in the generated code. For example, say a struct S has fields A and B.
|
|
The generated encoder would assign 0 to A and 1 to B, and include this comment in the code:
|
|
|
|
// Fields of S: A B
|
|
|
|
If later a field X was added between A and B, the generator would read the comment
|
|
and preserve the original assignments of A and B. It would assign 2 to X, and the
|
|
generated code would contain the new comment
|
|
|
|
// Fields of S: A B X
|
|
|
|
Values of type any are encoded as a pair of an assigned type number and the value.
|
|
All types that can appear as values must be registered by calling Register.
|
|
Type numbers are assigned to type names by the encoder in the order that types are encountered.
|
|
The assignments are saved at the beginning of the encoded data.
|
|
*/
|
|
package codec
|