mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
clean up for public use: make some stuff private, add doc comments.
R=rsc DELTA=298 (202 added, 0 deleted, 96 changed) OCL=32006 CL=32224
This commit is contained in:
parent
3ff5e727e2
commit
5aa174557a
7 changed files with 294 additions and 92 deletions
|
|
@ -36,6 +36,7 @@ var encodeT = []EncodeT {
|
|||
EncodeT{ 1<<63, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81} },
|
||||
}
|
||||
|
||||
|
||||
// Test basic encode/decode routines for unsigned integers
|
||||
func TestUintCodec(t *testing.T) {
|
||||
b := new(bytes.Buffer);
|
||||
|
|
@ -552,7 +553,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
b := new(bytes.Buffer);
|
||||
encode(b, t1);
|
||||
var _t1 T1;
|
||||
decode(b, getTypeInfo(reflect.Typeof(_t1)).typeId, &_t1);
|
||||
decode(b, getTypeInfo(reflect.Typeof(_t1)).id, &_t1);
|
||||
if !reflect.DeepEqual(t1, &_t1) {
|
||||
t.Errorf("encode expected %v got %v", *t1, _t1);
|
||||
}
|
||||
|
|
@ -570,7 +571,7 @@ func TestNesting(t *testing.T) {
|
|||
b := new(bytes.Buffer);
|
||||
encode(b, rt);
|
||||
var drt RT;
|
||||
decode(b, getTypeInfo(reflect.Typeof(drt)).typeId, &drt);
|
||||
decode(b, getTypeInfo(reflect.Typeof(drt)).id, &drt);
|
||||
if drt.a != rt.a {
|
||||
t.Errorf("nesting: encode expected %v got %v", *rt, drt);
|
||||
}
|
||||
|
|
@ -612,7 +613,7 @@ func TestAutoIndirection(t *testing.T) {
|
|||
b := new(bytes.Buffer);
|
||||
encode(b, t1);
|
||||
var t0 T0;
|
||||
t0Id := getTypeInfo(reflect.Typeof(t0)).typeId;
|
||||
t0Id := getTypeInfo(reflect.Typeof(t0)).id;
|
||||
decode(b, t0Id, &t0);
|
||||
if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
|
||||
t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0);
|
||||
|
|
@ -637,7 +638,7 @@ func TestAutoIndirection(t *testing.T) {
|
|||
b.Reset();
|
||||
encode(b, t0);
|
||||
t1 = T1{};
|
||||
t1Id := getTypeInfo(reflect.Typeof(t1)).typeId;
|
||||
t1Id := getTypeInfo(reflect.Typeof(t1)).id;
|
||||
decode(b, t1Id, &t1);
|
||||
if t1.a != 17 || *t1.b != 177 || **t1.c != 1777 || ***t1.d != 17777 {
|
||||
t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.a, *t1.b, **t1.c, ***t1.d);
|
||||
|
|
@ -647,7 +648,7 @@ func TestAutoIndirection(t *testing.T) {
|
|||
b.Reset();
|
||||
encode(b, t0);
|
||||
t2 = T2{};
|
||||
t2Id := getTypeInfo(reflect.Typeof(t2)).typeId;
|
||||
t2Id := getTypeInfo(reflect.Typeof(t2)).id;
|
||||
decode(b, t2Id, &t2);
|
||||
if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
|
||||
t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d);
|
||||
|
|
@ -685,7 +686,7 @@ func TestReorderedFields(t *testing.T) {
|
|||
rt0.c = 3.14159;
|
||||
b := new(bytes.Buffer);
|
||||
encode(b, rt0);
|
||||
rt0Id := getTypeInfo(reflect.Typeof(rt0)).typeId;
|
||||
rt0Id := getTypeInfo(reflect.Typeof(rt0)).id;
|
||||
var rt1 RT1;
|
||||
// Wire type is RT0, local type is RT1.
|
||||
decode(b, rt0Id, &rt1);
|
||||
|
|
@ -723,7 +724,7 @@ func TestIgnoredFields(t *testing.T) {
|
|||
|
||||
b := new(bytes.Buffer);
|
||||
encode(b, it0);
|
||||
rt0Id := getTypeInfo(reflect.Typeof(it0)).typeId;
|
||||
rt0Id := getTypeInfo(reflect.Typeof(it0)).id;
|
||||
var rt1 RT1;
|
||||
// Wire type is IT0, local type is RT1.
|
||||
err := decode(b, rt0Id, &rt1);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrRange = os.ErrorString("gob: internal error: field numbers out of bounds");
|
||||
ErrNotStruct = os.ErrorString("gob: TODO: can only handle structs")
|
||||
errRange = os.ErrorString("gob: internal error: field numbers out of bounds");
|
||||
errNotStruct = os.ErrorString("gob: TODO: can only handle structs")
|
||||
)
|
||||
|
||||
// The global execution state of an instance of the decoder.
|
||||
|
|
@ -347,7 +347,7 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
|
|||
}
|
||||
fieldnum := state.fieldnum + delta;
|
||||
if fieldnum >= len(engine.instr) {
|
||||
state.err = ErrRange;
|
||||
state.err = errRange;
|
||||
break;
|
||||
}
|
||||
instr := &engine.instr[fieldnum];
|
||||
|
|
@ -376,7 +376,7 @@ func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
|
|||
}
|
||||
fieldnum := state.fieldnum + delta;
|
||||
if fieldnum >= len(engine.instr) {
|
||||
state.err = ErrRange;
|
||||
state.err = errRange;
|
||||
break;
|
||||
}
|
||||
instr := &engine.instr[fieldnum];
|
||||
|
|
@ -474,7 +474,7 @@ var decOpMap = map[reflect.Type] decOp {
|
|||
reflect.Typeof((*reflect.StringType)(nil)): decString,
|
||||
}
|
||||
|
||||
var decIgnoreOpMap = map[TypeId] decOp {
|
||||
var decIgnoreOpMap = map[typeId] decOp {
|
||||
tBool: ignoreUint,
|
||||
tInt: ignoreUint,
|
||||
tUint: ignoreUint,
|
||||
|
|
@ -483,12 +483,12 @@ var decIgnoreOpMap = map[TypeId] decOp {
|
|||
tString: ignoreUint8Array,
|
||||
}
|
||||
|
||||
func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error)
|
||||
func getIgnoreEnginePtr(wireId TypeId) (enginePtr **decEngine, err os.Error)
|
||||
func getDecEnginePtr(wireId typeId, rt reflect.Type) (enginePtr **decEngine, err os.Error)
|
||||
func getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error)
|
||||
|
||||
// Return the decoding op for the base type under rt and
|
||||
// the indirection count to reach it.
|
||||
func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
|
||||
func decOpFor(wireId typeId, rt reflect.Type) (decOp, int, os.Error) {
|
||||
typ, indir := indirect(rt);
|
||||
op, ok := decOpMap[reflect.Typeof(typ)];
|
||||
if !ok {
|
||||
|
|
@ -537,7 +537,7 @@ func decOpFor(wireId TypeId, rt reflect.Type) (decOp, int, os.Error) {
|
|||
}
|
||||
|
||||
// Return the decoding op for a field that has no destination.
|
||||
func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
|
||||
func decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
|
||||
op, ok := decIgnoreOpMap[wireId];
|
||||
if !ok {
|
||||
// Special cases
|
||||
|
|
@ -583,7 +583,7 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
|
|||
// Are these two gob Types compatible?
|
||||
// Answers the question for basic types, arrays, and slices.
|
||||
// Structs are considered ok; fields will be checked later.
|
||||
func compatibleType(fr reflect.Type, fw TypeId) bool {
|
||||
func compatibleType(fr reflect.Type, fw typeId) bool {
|
||||
for {
|
||||
if pt, ok := fr.(*reflect.PtrType); ok {
|
||||
fr = pt.Elem();
|
||||
|
|
@ -645,11 +645,11 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error) {
|
||||
func compileDec(wireId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
|
||||
srt, ok1 := rt.(*reflect.StructType);
|
||||
wireStruct, ok2 := wireId.gobType().(*structType);
|
||||
if !ok1 || !ok2 {
|
||||
return nil, ErrNotStruct
|
||||
return nil, errNotStruct
|
||||
}
|
||||
engine = new(decEngine);
|
||||
engine.instr = make([]decInstr, len(wireStruct.field));
|
||||
|
|
@ -660,17 +660,17 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
|
|||
localField, present := srt.FieldByName(wireField.name);
|
||||
// TODO(r): anonymous names
|
||||
if !present || localField.Anonymous {
|
||||
op, err := decIgnoreOpFor(wireField.typeId);
|
||||
op, err := decIgnoreOpFor(wireField.id);
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
|
||||
continue;
|
||||
}
|
||||
if !compatibleType(localField.Type, wireField.typeId) {
|
||||
if !compatibleType(localField.Type, wireField.id) {
|
||||
return nil, os.ErrorString("gob: wrong type for field " + wireField.name + " in type " + wireId.Name());
|
||||
}
|
||||
op, indir, err := decOpFor(wireField.typeId, localField.Type);
|
||||
op, indir, err := decOpFor(wireField.id, localField.Type);
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -680,14 +680,14 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
|
|||
return;
|
||||
}
|
||||
|
||||
var decoderCache = make(map[reflect.Type] map[TypeId] **decEngine)
|
||||
var ignorerCache = make(map[TypeId] **decEngine)
|
||||
var decoderCache = make(map[reflect.Type] map[typeId] **decEngine)
|
||||
var ignorerCache = make(map[typeId] **decEngine)
|
||||
|
||||
// typeLock must be held.
|
||||
func getDecEnginePtr(wireId TypeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
|
||||
func getDecEnginePtr(wireId typeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
|
||||
decoderMap, ok := decoderCache[rt];
|
||||
if !ok {
|
||||
decoderMap = make(map[TypeId] **decEngine);
|
||||
decoderMap = make(map[typeId] **decEngine);
|
||||
decoderCache[rt] = decoderMap;
|
||||
}
|
||||
if enginePtr, ok = decoderMap[wireId]; !ok {
|
||||
|
|
@ -707,7 +707,7 @@ type emptyStruct struct {}
|
|||
var emptyStructType = reflect.Typeof(emptyStruct{})
|
||||
|
||||
// typeLock must be held.
|
||||
func getIgnoreEnginePtr(wireId TypeId) (enginePtr **decEngine, err os.Error) {
|
||||
func getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
|
||||
var ok bool;
|
||||
if enginePtr, ok = ignorerCache[wireId]; !ok {
|
||||
// To handle recursive types, mark this engine as underway before compiling.
|
||||
|
|
@ -721,7 +721,7 @@ func getIgnoreEnginePtr(wireId TypeId) (enginePtr **decEngine, err os.Error) {
|
|||
return
|
||||
}
|
||||
|
||||
func decode(b *bytes.Buffer, wireId TypeId, e interface{}) os.Error {
|
||||
func decode(b *bytes.Buffer, wireId typeId, e interface{}) os.Error {
|
||||
// Dereference down to the underlying object.
|
||||
rt, indir := indirect(reflect.Typeof(e));
|
||||
v := reflect.NewValue(e);
|
||||
|
|
|
|||
|
|
@ -13,27 +13,30 @@ import (
|
|||
"sync";
|
||||
)
|
||||
|
||||
// A Decoder manages the receipt of type and data information read from the
|
||||
// remote side of a connection.
|
||||
type Decoder struct {
|
||||
sync.Mutex; // each item must be received atomically
|
||||
mutex sync.Mutex; // each item must be received atomically
|
||||
r io.Reader; // source of the data
|
||||
seen map[TypeId] *wireType; // which types we've already seen described
|
||||
seen map[typeId] *wireType; // which types we've already seen described
|
||||
state *decodeState; // reads data from in-memory buffer
|
||||
countState *decodeState; // reads counts from wire
|
||||
buf []byte;
|
||||
oneByte []byte;
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from the io.Reader.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
dec := new(Decoder);
|
||||
dec.r = r;
|
||||
dec.seen = make(map[TypeId] *wireType);
|
||||
dec.seen = make(map[typeId] *wireType);
|
||||
dec.state = new(decodeState); // buffer set in Decode(); rest is unimportant
|
||||
dec.oneByte = make([]byte, 1);
|
||||
|
||||
return dec;
|
||||
}
|
||||
|
||||
func (dec *Decoder) recvType(id TypeId) {
|
||||
func (dec *Decoder) recvType(id typeId) {
|
||||
// Have we already seen this type? That's an error
|
||||
if wt_, alreadySeen := dec.seen[id]; alreadySeen {
|
||||
dec.state.err = os.ErrorString("gob: duplicate type received");
|
||||
|
|
@ -47,14 +50,16 @@ func (dec *Decoder) recvType(id TypeId) {
|
|||
dec.seen[id] = wire;
|
||||
}
|
||||
|
||||
// Decode reads the next value from the connection and stores
|
||||
// it in the data represented by the empty interface value.
|
||||
// The value underlying e must be the correct type for the next
|
||||
// value to be received for this decoder.
|
||||
// data item received.
|
||||
func (dec *Decoder) Decode(e interface{}) os.Error {
|
||||
rt, indir := indirect(reflect.Typeof(e));
|
||||
|
||||
// Make sure we're single-threaded through here.
|
||||
dec.Lock();
|
||||
defer dec.Unlock();
|
||||
dec.mutex.Lock();
|
||||
defer dec.mutex.Unlock();
|
||||
|
||||
dec.state.err = nil;
|
||||
for {
|
||||
|
|
@ -81,7 +86,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
|
|||
}
|
||||
|
||||
// Receive a type id.
|
||||
id := TypeId(decodeInt(dec.state));
|
||||
id := typeId(decodeInt(dec.state));
|
||||
if dec.state.err != nil {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,183 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
The gob package manages streams of gobs - binary values exchanged between an
|
||||
Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
|
||||
arguments and results of remote procedure calls (RPCs) such as those provided by
|
||||
package "rpc".
|
||||
|
||||
A stream of gobs is self-describing. Each data item in the stream is preceded by
|
||||
a specification of its type, expressed in terms of a small set of predefined
|
||||
types. Pointers are not transmitted, but the things they point to are
|
||||
transmitted; that is, the values are flattened. Recursive types work fine, but
|
||||
recursive values (data with cycles) are problematic. This may change.
|
||||
|
||||
To use gobs, create an Encoder and present it with a series of data items as
|
||||
values or addresses that can be dereferenced to values. (At the moment, these
|
||||
items must be structs (struct, *struct, **struct etc.), but this may change.) The
|
||||
Encoder makes sure all type information is sent before it is needed. At the
|
||||
receive side, a Decoder retrieves values from the encoded stream and unpacks them
|
||||
into local variables.
|
||||
|
||||
The source and destination values/types need not correspond exactly. For structs,
|
||||
fields (identified by name) that are in the source but absent from the receiving
|
||||
variable will be ignored. Fields that are in the receiving variable but missing
|
||||
from the transmitted type or value will be ignored in the destination. If a field
|
||||
with the same name is present in both, their types must be compatible. Both the
|
||||
receiver and transmitter will do all necessary indirection and dereferencing to
|
||||
convert between gobs and actual Go values. For instance, a gob type that is
|
||||
schematically,
|
||||
|
||||
struct { a, b int }
|
||||
|
||||
can be sent from or received into any of these Go types:
|
||||
|
||||
struct { a, b int } // the same
|
||||
*struct { a, b int } // extra indirection of the struct
|
||||
struct { *a, **b int } // extra indirection of the fields
|
||||
struct { a, b int64 } // different concrete value type; see below
|
||||
|
||||
It may also be received into any of these:
|
||||
|
||||
struct { a, b int } // the same
|
||||
struct { b, a int } // ordering doesn't matter; matching is by name
|
||||
struct { a, b, c int } // extra field (c) ignored
|
||||
struct { b int } // missing field (a) ignored; data will be dropped
|
||||
struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
|
||||
|
||||
Attempting to receive into these types will draw a decode error:
|
||||
|
||||
struct { a int; b uint } // change of signedness for b
|
||||
struct { a int; b float } // change of type for b
|
||||
struct { } // no field names in common
|
||||
struct { c, d int } // no field names in common
|
||||
|
||||
Integers are transmitted two ways: arbitrary precision signed integers or
|
||||
arbitrary precision unsigned integers. There is no int8, int16 etc.
|
||||
discrimination in the gob format; there are only signed and unsigned integers. As
|
||||
described below, the transmitter sends the value in a variable-length encoding;
|
||||
the receiver accepts the value and stores it in the destination variable.
|
||||
Floating-point numbers are always sent using IEEE-754 64-bit precision (see
|
||||
below).
|
||||
|
||||
Signed integers may be received into any signed integer variable: int, int16, etc.;
|
||||
unsigned integers may be received into any unsigned integer variable; and floating
|
||||
point values may be received into any floating point variable. However,
|
||||
the destination variable must be able to represent the value or the decode
|
||||
operation will fail. (TODO(r): enforce this.)
|
||||
|
||||
Structs, arrays and slices are also supported. Strings and arrays of bytes are
|
||||
supported with a special, efficient representation (see below).
|
||||
|
||||
Maps are not supported yet, but they will be. Interfaces, functions, and channels
|
||||
cannot be sent in a gob. Attempting to encode a value that contains one will
|
||||
fail. (TODO(r): fix this - it panics now.)
|
||||
|
||||
The rest of this comment documents the encoding, details that are not important
|
||||
for most users. Details are presented bottom-up.
|
||||
|
||||
An unsigned integer is encoded as an arbitrary-precision, variable-length sequence
|
||||
of bytes. It is sent in little-endian order (low bits first), with seven bits per
|
||||
byte. The high bit of each byte is zero, except that the high bit of the final
|
||||
(highest precision) byte of the encoding will be set. Thus 0 is transmitted as
|
||||
(80), 7 is transmitted as (87) and 256=2*128 is transmitted as (00 82).
|
||||
|
||||
A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
|
||||
|
||||
A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
|
||||
upward contain the value; bit 0 says whether they should be complemented upon
|
||||
receipt. The encode algorithm looks like this:
|
||||
|
||||
uint u;
|
||||
if i < 0 {
|
||||
u = (^i << 1) | 1 // complement i, bit 0 is 1
|
||||
} else {
|
||||
u = (i << 1) // do not complement i, bit 0 is 0
|
||||
}
|
||||
encodeUnsigned(u)
|
||||
|
||||
The low bit is therefore analogous to a sign bit, but making it the complement bit
|
||||
instead guarantees that the largest negative integer is not a special case. For
|
||||
example, -129=^128=(^256>>1) encodes as (01 82).
|
||||
|
||||
Floating-point numbers are always sent as a representation of a float64 value.
|
||||
That value is converted to a uint64 using math.Float64bits. The uint64 is then
|
||||
byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
|
||||
exponent and high-precision part of the mantissa go first. Since the low bits are
|
||||
often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
|
||||
two bytes (40 e2).
|
||||
|
||||
Strings and slices of bytes are sent as an unsigned count followed by that many
|
||||
uninterpreted bytes of the value.
|
||||
|
||||
All other slices and arrays are sent as an unsigned count followed by that many
|
||||
elements using the standard gob encoding for their type, recursively.
|
||||
|
||||
Structs are sent as a sequence of (field number, field value) pairs. The field
|
||||
value is sent using the standard gob encoding for its type, recursively. If a
|
||||
field has the zero value for its type, it is omitted from the transmission. The
|
||||
field number is defined by the type of the encoded struct: the first field of the
|
||||
encoded type is field 0, the second is field 1, etc. When encoding a value, the
|
||||
field numbers are delta encoded for efficiency and the fields are always sent in
|
||||
order of increasing field number; the deltas are therefore unsigned. The
|
||||
initialization for the delta encoding sets the field number to -1, so an unsigned
|
||||
integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
|
||||
= 7 or (81 87). Finally, after all the fields have been sent a terminating mark
|
||||
denotes the end of the struct. That mark is a delta=0 value, which has
|
||||
representation (80).
|
||||
|
||||
The representation of types is described below. When a type is defined on a given
|
||||
connection between an Encoder and Decoder, it is assigned a signed integer type
|
||||
id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
|
||||
the type of v and all its elements and then it sends the pair (typeid, encoded-v)
|
||||
where typeid is the type id of the encoded type of v and encoded-v is the gob
|
||||
encoding of the value v.
|
||||
|
||||
To define a type, the encoder chooses an unused, positive type id and sends the
|
||||
pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
|
||||
description, constructed from these types:
|
||||
|
||||
type wireType struct {
|
||||
s structType;
|
||||
}
|
||||
type fieldType struct {
|
||||
name string; // the name of the field.
|
||||
id int; // the type id of the field, which must be already defined
|
||||
}
|
||||
type commonType {
|
||||
name string; // the name of the struct type
|
||||
id int; // the id of the type, repeated for so it's inside the type
|
||||
}
|
||||
type structType struct {
|
||||
commonType;
|
||||
field []fieldType; // the fields of the struct.
|
||||
}
|
||||
|
||||
If there are nested type ids, the types for all inner type ids must be defined
|
||||
before the top-level type id is used to describe an encoded-v.
|
||||
|
||||
For simplicity in setup, the connection is defined to understand these types a
|
||||
priori, as well as the basic gob types int, uint, etc. Their ids are:
|
||||
|
||||
bool 1
|
||||
int 2
|
||||
uint 3
|
||||
float 4
|
||||
[]byte 5
|
||||
string 6
|
||||
wireType 7
|
||||
structType 8
|
||||
commonType 9
|
||||
fieldType 10
|
||||
|
||||
In summary, a gob stream looks like
|
||||
|
||||
((-type id, encoding of a wireType)* (type id, encoding of a value))*
|
||||
|
||||
where * signifies zero or more repetitions and the type id of a value must
|
||||
be predefined or be defined before the value in the stream.
|
||||
*/
|
||||
package gob
|
||||
|
||||
import (
|
||||
|
|
@ -13,19 +190,22 @@ import (
|
|||
"sync";
|
||||
)
|
||||
|
||||
// An Encoder manages the transmission of type and data information to the
|
||||
// other side of a connection.
|
||||
type Encoder struct {
|
||||
sync.Mutex; // each item must be sent atomically
|
||||
mutex sync.Mutex; // each item must be sent atomically
|
||||
w io.Writer; // where to send the data
|
||||
sent map[reflect.Type] TypeId; // which types we've already sent
|
||||
sent map[reflect.Type] typeId; // which types we've already sent
|
||||
state *encoderState; // so we can encode integers, strings directly
|
||||
countState *encoderState; // stage for writing counts
|
||||
buf []byte; // for collecting the output.
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that will transmit on the io.Writer.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
enc := new(Encoder);
|
||||
enc.w = w;
|
||||
enc.sent = make(map[reflect.Type] TypeId);
|
||||
enc.sent = make(map[reflect.Type] typeId);
|
||||
enc.state = new(encoderState);
|
||||
enc.state.b = new(bytes.Buffer); // the rest isn't important; all we need is buffer and writer
|
||||
enc.countState = new(encoderState);
|
||||
|
|
@ -91,15 +271,15 @@ func (enc *Encoder) sendType(origt reflect.Type) {
|
|||
typeLock.Unlock();
|
||||
// Send the pair (-id, type)
|
||||
// Id:
|
||||
encodeInt(enc.state, -int64(info.typeId));
|
||||
encodeInt(enc.state, -int64(info.id));
|
||||
// Type:
|
||||
encode(enc.state.b, info.wire);
|
||||
enc.send();
|
||||
|
||||
// Remember we've sent this type.
|
||||
enc.sent[rt] = info.typeId;
|
||||
enc.sent[rt] = info.id;
|
||||
// Remember we've sent the top-level, possibly indirect type too.
|
||||
enc.sent[origt] = info.typeId;
|
||||
enc.sent[origt] = info.id;
|
||||
// Now send the inner types
|
||||
st := rt.(*reflect.StructType);
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
|
|
@ -107,6 +287,8 @@ func (enc *Encoder) sendType(origt reflect.Type) {
|
|||
}
|
||||
}
|
||||
|
||||
// Encode transmits the data item represented by the empty interface value,
|
||||
// guaranteeing that all necessary type information has been transmitted first.
|
||||
func (enc *Encoder) Encode(e interface{}) os.Error {
|
||||
if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
|
||||
panicln("Encoder: buffer not empty")
|
||||
|
|
@ -114,8 +296,8 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
|
|||
rt, indir := indirect(reflect.Typeof(e));
|
||||
|
||||
// Make sure we're single-threaded through here.
|
||||
enc.Lock();
|
||||
defer enc.Unlock();
|
||||
enc.mutex.Lock();
|
||||
defer enc.mutex.Unlock();
|
||||
|
||||
// Make sure the type is known to the other side.
|
||||
// First, have we already sent this type?
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func TestBasicEncoder(t *testing.T) {
|
|||
t.Fatal("error decoding ET1 type:", err);
|
||||
}
|
||||
info := getTypeInfo(reflect.Typeof(ET1{}));
|
||||
trueWire1 := &wireType{s: info.typeId.gobType().(*structType)};
|
||||
trueWire1 := &wireType{s: info.id.gobType().(*structType)};
|
||||
if !reflect.DeepEqual(wire1, trueWire1) {
|
||||
t.Fatalf("invalid wireType for ET1: expected %+v; got %+v\n", *trueWire1, *wire1);
|
||||
}
|
||||
|
|
@ -91,7 +91,7 @@ func TestBasicEncoder(t *testing.T) {
|
|||
t.Fatal("error decoding ET2 type:", err);
|
||||
}
|
||||
info = getTypeInfo(reflect.Typeof(ET2{}));
|
||||
trueWire2 := &wireType{s: info.typeId.gobType().(*structType)};
|
||||
trueWire2 := &wireType{s: info.id.gobType().(*structType)};
|
||||
if !reflect.DeepEqual(wire2, trueWire2) {
|
||||
t.Fatalf("invalid wireType for ET2: expected %+v; got %+v\n", *trueWire2, *wire2);
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ func TestBasicEncoder(t *testing.T) {
|
|||
}
|
||||
// 8) The value of et1
|
||||
newEt1 := new(ET1);
|
||||
et1Id := getTypeInfo(reflect.Typeof(*newEt1)).typeId;
|
||||
et1Id := getTypeInfo(reflect.Typeof(*newEt1)).id;
|
||||
err = decode(b, et1Id, newEt1);
|
||||
if err != nil {
|
||||
t.Fatal("error decoding ET1 value:", err);
|
||||
|
|
|
|||
|
|
@ -13,23 +13,23 @@ import (
|
|||
"unicode";
|
||||
)
|
||||
|
||||
// Types are identified by an integer TypeId. These can be passed on the wire.
|
||||
// Internally, they are used as keys to a map to recover the underlying type info.
|
||||
type TypeId int32
|
||||
// A typeId represents a gob Type as an integer that can be passed on the wire.
|
||||
// Internally, typeIds are used as keys to a map to recover the underlying type info.
|
||||
type typeId int32
|
||||
|
||||
var nextId TypeId // incremented for each new type we build
|
||||
var nextId typeId // incremented for each new type we build
|
||||
var typeLock sync.Mutex // set while building a type
|
||||
|
||||
type gobType interface {
|
||||
id() TypeId;
|
||||
setId(id TypeId);
|
||||
id() typeId;
|
||||
setId(id typeId);
|
||||
Name() string;
|
||||
String() string;
|
||||
safeString(seen map[TypeId] bool) string;
|
||||
safeString(seen map[typeId] bool) string;
|
||||
}
|
||||
|
||||
var types = make(map[reflect.Type] gobType)
|
||||
var idToType = make(map[TypeId] gobType)
|
||||
var idToType = make(map[typeId] gobType)
|
||||
|
||||
func setTypeId(typ gobType) {
|
||||
nextId++;
|
||||
|
|
@ -37,32 +37,34 @@ func setTypeId(typ gobType) {
|
|||
idToType[nextId] = typ;
|
||||
}
|
||||
|
||||
func (t TypeId) gobType() gobType {
|
||||
func (t typeId) gobType() gobType {
|
||||
if t == 0 {
|
||||
return nil
|
||||
}
|
||||
return idToType[t]
|
||||
}
|
||||
|
||||
func (t TypeId) String() string {
|
||||
// String returns the string representation of the type associated with the typeId.
|
||||
func (t typeId) String() string {
|
||||
return t.gobType().String()
|
||||
}
|
||||
|
||||
func (t TypeId) Name() string {
|
||||
// Name returns the name of the type associated with the typeId.
|
||||
func (t typeId) Name() string {
|
||||
return t.gobType().Name()
|
||||
}
|
||||
|
||||
// Common elements of all types.
|
||||
type commonType struct {
|
||||
name string;
|
||||
_id TypeId;
|
||||
_id typeId;
|
||||
}
|
||||
|
||||
func (t *commonType) id() TypeId {
|
||||
func (t *commonType) id() typeId {
|
||||
return t._id
|
||||
}
|
||||
|
||||
func (t *commonType) setId(id TypeId) {
|
||||
func (t *commonType) setId(id typeId) {
|
||||
t._id = id
|
||||
}
|
||||
|
||||
|
|
@ -79,20 +81,20 @@ func (t *commonType) Name() string {
|
|||
}
|
||||
|
||||
// Basic type identifiers, predefined.
|
||||
var tBool TypeId
|
||||
var tInt TypeId
|
||||
var tUint TypeId
|
||||
var tFloat TypeId
|
||||
var tString TypeId
|
||||
var tBytes TypeId
|
||||
var tBool typeId
|
||||
var tInt typeId
|
||||
var tUint typeId
|
||||
var tFloat typeId
|
||||
var tString typeId
|
||||
var tBytes typeId
|
||||
|
||||
// Predefined because it's needed by the Decoder
|
||||
var tWireType TypeId
|
||||
var tWireType typeId
|
||||
|
||||
// Array type
|
||||
type arrayType struct {
|
||||
commonType;
|
||||
Elem TypeId;
|
||||
Elem typeId;
|
||||
Len int;
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +104,7 @@ func newArrayType(name string, elem gobType, length int) *arrayType {
|
|||
return a;
|
||||
}
|
||||
|
||||
func (a *arrayType) safeString(seen map[TypeId] bool) string {
|
||||
func (a *arrayType) safeString(seen map[typeId] bool) string {
|
||||
if _, ok := seen[a._id]; ok {
|
||||
return a.name
|
||||
}
|
||||
|
|
@ -117,7 +119,7 @@ func (a *arrayType) String() string {
|
|||
// Slice type
|
||||
type sliceType struct {
|
||||
commonType;
|
||||
Elem TypeId;
|
||||
Elem typeId;
|
||||
}
|
||||
|
||||
func newSliceType(name string, elem gobType) *sliceType {
|
||||
|
|
@ -126,7 +128,7 @@ func newSliceType(name string, elem gobType) *sliceType {
|
|||
return s;
|
||||
}
|
||||
|
||||
func (s *sliceType) safeString(seen map[TypeId] bool) string {
|
||||
func (s *sliceType) safeString(seen map[typeId] bool) string {
|
||||
if _, ok := seen[s._id]; ok {
|
||||
return s.name
|
||||
}
|
||||
|
|
@ -135,13 +137,13 @@ func (s *sliceType) safeString(seen map[TypeId] bool) string {
|
|||
}
|
||||
|
||||
func (s *sliceType) String() string {
|
||||
return s.safeString(make(map[TypeId] bool))
|
||||
return s.safeString(make(map[typeId] bool))
|
||||
}
|
||||
|
||||
// Struct type
|
||||
type fieldType struct {
|
||||
name string;
|
||||
typeId TypeId;
|
||||
id typeId;
|
||||
}
|
||||
|
||||
type structType struct {
|
||||
|
|
@ -149,7 +151,7 @@ type structType struct {
|
|||
field []*fieldType;
|
||||
}
|
||||
|
||||
func (s *structType) safeString(seen map[TypeId] bool) string {
|
||||
func (s *structType) safeString(seen map[typeId] bool) string {
|
||||
if s == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
|
@ -159,14 +161,14 @@ func (s *structType) safeString(seen map[TypeId] bool) string {
|
|||
seen[s._id] = true;
|
||||
str := s.name + " = struct { ";
|
||||
for _, f := range s.field {
|
||||
str += fmt.Sprintf("%s %s; ", f.name, f.typeId.gobType().safeString(seen));
|
||||
str += fmt.Sprintf("%s %s; ", f.name, f.id.gobType().safeString(seen));
|
||||
}
|
||||
str += "}";
|
||||
return str;
|
||||
}
|
||||
|
||||
func (s *structType) String() string {
|
||||
return s.safeString(make(map[TypeId] bool))
|
||||
return s.safeString(make(map[typeId] bool))
|
||||
}
|
||||
|
||||
func newStructType(name string) *structType {
|
||||
|
|
@ -294,8 +296,14 @@ func getType(name string, rt reflect.Type) gobType {
|
|||
return t;
|
||||
}
|
||||
|
||||
func checkId(want, got typeId) {
|
||||
if want != got {
|
||||
panicln("bootstrap type wrong id:", got.Name(), got, "not", want);
|
||||
}
|
||||
}
|
||||
|
||||
// used for building the basic types; called only from init()
|
||||
func bootstrapType(name string, e interface{}) TypeId {
|
||||
func bootstrapType(name string, e interface{}, expect typeId) typeId {
|
||||
rt := reflect.Typeof(e);
|
||||
_, present := types[rt];
|
||||
if present {
|
||||
|
|
@ -304,6 +312,7 @@ func bootstrapType(name string, e interface{}) TypeId {
|
|||
typ := &commonType{ name: name };
|
||||
types[rt] = typ;
|
||||
setTypeId(typ);
|
||||
checkId(expect, nextId);
|
||||
return nextId
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +338,7 @@ func (w *wireType) name() string {
|
|||
type decEngine struct // defined in decode.go
|
||||
type encEngine struct // defined in encode.go
|
||||
type typeInfo struct {
|
||||
typeId TypeId;
|
||||
id typeId;
|
||||
encoder *encEngine;
|
||||
wire *wireType;
|
||||
}
|
||||
|
|
@ -346,21 +355,26 @@ func getTypeInfo(rt reflect.Type) *typeInfo {
|
|||
if !ok {
|
||||
info = new(typeInfo);
|
||||
name := rt.Name();
|
||||
info.typeId = getType(name, rt).id();
|
||||
info.id = getType(name, rt).id();
|
||||
// assume it's a struct type
|
||||
info.wire = &wireType{info.typeId.gobType().(*structType)};
|
||||
info.wire = &wireType{info.id.gobType().(*structType)};
|
||||
typeInfoMap[rt] = info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
func init() {
|
||||
tBool = bootstrapType("bool", false);
|
||||
tInt = bootstrapType("int", int(0));
|
||||
tUint = bootstrapType("uint", uint(0));
|
||||
tFloat = bootstrapType("float", float64(0));
|
||||
// Create and check predefined types
|
||||
tBool = bootstrapType("bool", false, 1);
|
||||
tInt = bootstrapType("int", int(0), 2);
|
||||
tUint = bootstrapType("uint", uint(0), 3);
|
||||
tFloat = bootstrapType("float", float64(0), 4);
|
||||
// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
|
||||
tBytes = bootstrapType("bytes", make([]byte, 0));
|
||||
tString= bootstrapType("string", "");
|
||||
tWireType = getTypeInfo(reflect.Typeof(wireType{})).typeId;
|
||||
tBytes = bootstrapType("bytes", make([]byte, 0), 5);
|
||||
tString= bootstrapType("string", "", 6);
|
||||
tWireType = getTypeInfo(reflect.Typeof(wireType{})).id;
|
||||
checkId(7, tWireType);
|
||||
checkId(8, getTypeInfo(reflect.Typeof(structType{})).id);
|
||||
checkId(9, getTypeInfo(reflect.Typeof(commonType{})).id);
|
||||
checkId(10, getTypeInfo(reflect.Typeof(fieldType{})).id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
type typeT struct {
|
||||
typeId TypeId;
|
||||
id typeId;
|
||||
str string;
|
||||
}
|
||||
var basicTypes = []typeT {
|
||||
|
|
@ -33,10 +33,10 @@ func getTypeUnlocked(name string, rt reflect.Type) gobType {
|
|||
// Sanity checks
|
||||
func TestBasic(t *testing.T) {
|
||||
for _, tt := range basicTypes {
|
||||
if tt.typeId.String() != tt.str {
|
||||
t.Errorf("checkType: expected %q got %s", tt.str, tt.typeId.String())
|
||||
if tt.id.String() != tt.str {
|
||||
t.Errorf("checkType: expected %q got %s", tt.str, tt.id.String())
|
||||
}
|
||||
if tt.typeId == 0 {
|
||||
if tt.id == 0 {
|
||||
t.Errorf("id for %q is zero", tt.str)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue