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} },
|
EncodeT{ 1<<63, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81} },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Test basic encode/decode routines for unsigned integers
|
// Test basic encode/decode routines for unsigned integers
|
||||||
func TestUintCodec(t *testing.T) {
|
func TestUintCodec(t *testing.T) {
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
|
|
@ -552,7 +553,7 @@ func TestEndToEnd(t *testing.T) {
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
encode(b, t1);
|
encode(b, t1);
|
||||||
var _t1 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) {
|
if !reflect.DeepEqual(t1, &_t1) {
|
||||||
t.Errorf("encode expected %v got %v", *t1, _t1);
|
t.Errorf("encode expected %v got %v", *t1, _t1);
|
||||||
}
|
}
|
||||||
|
|
@ -570,7 +571,7 @@ func TestNesting(t *testing.T) {
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
encode(b, rt);
|
encode(b, rt);
|
||||||
var drt 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 {
|
if drt.a != rt.a {
|
||||||
t.Errorf("nesting: encode expected %v got %v", *rt, drt);
|
t.Errorf("nesting: encode expected %v got %v", *rt, drt);
|
||||||
}
|
}
|
||||||
|
|
@ -612,7 +613,7 @@ func TestAutoIndirection(t *testing.T) {
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
encode(b, t1);
|
encode(b, t1);
|
||||||
var t0 T0;
|
var t0 T0;
|
||||||
t0Id := getTypeInfo(reflect.Typeof(t0)).typeId;
|
t0Id := getTypeInfo(reflect.Typeof(t0)).id;
|
||||||
decode(b, t0Id, &t0);
|
decode(b, t0Id, &t0);
|
||||||
if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
|
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);
|
t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0);
|
||||||
|
|
@ -637,7 +638,7 @@ func TestAutoIndirection(t *testing.T) {
|
||||||
b.Reset();
|
b.Reset();
|
||||||
encode(b, t0);
|
encode(b, t0);
|
||||||
t1 = T1{};
|
t1 = T1{};
|
||||||
t1Id := getTypeInfo(reflect.Typeof(t1)).typeId;
|
t1Id := getTypeInfo(reflect.Typeof(t1)).id;
|
||||||
decode(b, t1Id, &t1);
|
decode(b, t1Id, &t1);
|
||||||
if t1.a != 17 || *t1.b != 177 || **t1.c != 1777 || ***t1.d != 17777 {
|
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);
|
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();
|
b.Reset();
|
||||||
encode(b, t0);
|
encode(b, t0);
|
||||||
t2 = T2{};
|
t2 = T2{};
|
||||||
t2Id := getTypeInfo(reflect.Typeof(t2)).typeId;
|
t2Id := getTypeInfo(reflect.Typeof(t2)).id;
|
||||||
decode(b, t2Id, &t2);
|
decode(b, t2Id, &t2);
|
||||||
if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
|
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);
|
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;
|
rt0.c = 3.14159;
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
encode(b, rt0);
|
encode(b, rt0);
|
||||||
rt0Id := getTypeInfo(reflect.Typeof(rt0)).typeId;
|
rt0Id := getTypeInfo(reflect.Typeof(rt0)).id;
|
||||||
var rt1 RT1;
|
var rt1 RT1;
|
||||||
// Wire type is RT0, local type is RT1.
|
// Wire type is RT0, local type is RT1.
|
||||||
decode(b, rt0Id, &rt1);
|
decode(b, rt0Id, &rt1);
|
||||||
|
|
@ -723,7 +724,7 @@ func TestIgnoredFields(t *testing.T) {
|
||||||
|
|
||||||
b := new(bytes.Buffer);
|
b := new(bytes.Buffer);
|
||||||
encode(b, it0);
|
encode(b, it0);
|
||||||
rt0Id := getTypeInfo(reflect.Typeof(it0)).typeId;
|
rt0Id := getTypeInfo(reflect.Typeof(it0)).id;
|
||||||
var rt1 RT1;
|
var rt1 RT1;
|
||||||
// Wire type is IT0, local type is RT1.
|
// Wire type is IT0, local type is RT1.
|
||||||
err := decode(b, rt0Id, &rt1);
|
err := decode(b, rt0Id, &rt1);
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrRange = os.ErrorString("gob: internal error: field numbers out of bounds");
|
errRange = os.ErrorString("gob: internal error: field numbers out of bounds");
|
||||||
ErrNotStruct = os.ErrorString("gob: TODO: can only handle structs")
|
errNotStruct = os.ErrorString("gob: TODO: can only handle structs")
|
||||||
)
|
)
|
||||||
|
|
||||||
// The global execution state of an instance of the decoder.
|
// 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;
|
fieldnum := state.fieldnum + delta;
|
||||||
if fieldnum >= len(engine.instr) {
|
if fieldnum >= len(engine.instr) {
|
||||||
state.err = ErrRange;
|
state.err = errRange;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instr := &engine.instr[fieldnum];
|
instr := &engine.instr[fieldnum];
|
||||||
|
|
@ -376,7 +376,7 @@ func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
|
||||||
}
|
}
|
||||||
fieldnum := state.fieldnum + delta;
|
fieldnum := state.fieldnum + delta;
|
||||||
if fieldnum >= len(engine.instr) {
|
if fieldnum >= len(engine.instr) {
|
||||||
state.err = ErrRange;
|
state.err = errRange;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
instr := &engine.instr[fieldnum];
|
instr := &engine.instr[fieldnum];
|
||||||
|
|
@ -474,7 +474,7 @@ var decOpMap = map[reflect.Type] decOp {
|
||||||
reflect.Typeof((*reflect.StringType)(nil)): decString,
|
reflect.Typeof((*reflect.StringType)(nil)): decString,
|
||||||
}
|
}
|
||||||
|
|
||||||
var decIgnoreOpMap = map[TypeId] decOp {
|
var decIgnoreOpMap = map[typeId] decOp {
|
||||||
tBool: ignoreUint,
|
tBool: ignoreUint,
|
||||||
tInt: ignoreUint,
|
tInt: ignoreUint,
|
||||||
tUint: ignoreUint,
|
tUint: ignoreUint,
|
||||||
|
|
@ -483,12 +483,12 @@ var decIgnoreOpMap = map[TypeId] decOp {
|
||||||
tString: ignoreUint8Array,
|
tString: ignoreUint8Array,
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDecEnginePtr(wireId TypeId, rt reflect.Type) (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)
|
func getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error)
|
||||||
|
|
||||||
// Return the decoding op for the base type under rt and
|
// Return the decoding op for the base type under rt and
|
||||||
// the indirection count to reach it.
|
// 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);
|
typ, indir := indirect(rt);
|
||||||
op, ok := decOpMap[reflect.Typeof(typ)];
|
op, ok := decOpMap[reflect.Typeof(typ)];
|
||||||
if !ok {
|
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.
|
// 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];
|
op, ok := decIgnoreOpMap[wireId];
|
||||||
if !ok {
|
if !ok {
|
||||||
// Special cases
|
// Special cases
|
||||||
|
|
@ -583,7 +583,7 @@ func decIgnoreOpFor(wireId TypeId) (decOp, os.Error) {
|
||||||
// Are these two gob Types compatible?
|
// Are these two gob Types compatible?
|
||||||
// Answers the question for basic types, arrays, and slices.
|
// Answers the question for basic types, arrays, and slices.
|
||||||
// Structs are considered ok; fields will be checked later.
|
// 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 {
|
for {
|
||||||
if pt, ok := fr.(*reflect.PtrType); ok {
|
if pt, ok := fr.(*reflect.PtrType); ok {
|
||||||
fr = pt.Elem();
|
fr = pt.Elem();
|
||||||
|
|
@ -645,11 +645,11 @@ func compatibleType(fr reflect.Type, fw TypeId) bool {
|
||||||
return true;
|
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);
|
srt, ok1 := rt.(*reflect.StructType);
|
||||||
wireStruct, ok2 := wireId.gobType().(*structType);
|
wireStruct, ok2 := wireId.gobType().(*structType);
|
||||||
if !ok1 || !ok2 {
|
if !ok1 || !ok2 {
|
||||||
return nil, ErrNotStruct
|
return nil, errNotStruct
|
||||||
}
|
}
|
||||||
engine = new(decEngine);
|
engine = new(decEngine);
|
||||||
engine.instr = make([]decInstr, len(wireStruct.field));
|
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);
|
localField, present := srt.FieldByName(wireField.name);
|
||||||
// TODO(r): anonymous names
|
// TODO(r): anonymous names
|
||||||
if !present || localField.Anonymous {
|
if !present || localField.Anonymous {
|
||||||
op, err := decIgnoreOpFor(wireField.typeId);
|
op, err := decIgnoreOpFor(wireField.id);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
|
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0};
|
||||||
continue;
|
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());
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -680,14 +680,14 @@ func compileDec(wireId TypeId, rt reflect.Type) (engine *decEngine, err os.Error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var decoderCache = make(map[reflect.Type] map[TypeId] **decEngine)
|
var decoderCache = make(map[reflect.Type] map[typeId] **decEngine)
|
||||||
var ignorerCache = make(map[TypeId] **decEngine)
|
var ignorerCache = make(map[typeId] **decEngine)
|
||||||
|
|
||||||
// typeLock must be held.
|
// 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];
|
decoderMap, ok := decoderCache[rt];
|
||||||
if !ok {
|
if !ok {
|
||||||
decoderMap = make(map[TypeId] **decEngine);
|
decoderMap = make(map[typeId] **decEngine);
|
||||||
decoderCache[rt] = decoderMap;
|
decoderCache[rt] = decoderMap;
|
||||||
}
|
}
|
||||||
if enginePtr, ok = decoderMap[wireId]; !ok {
|
if enginePtr, ok = decoderMap[wireId]; !ok {
|
||||||
|
|
@ -707,7 +707,7 @@ type emptyStruct struct {}
|
||||||
var emptyStructType = reflect.Typeof(emptyStruct{})
|
var emptyStructType = reflect.Typeof(emptyStruct{})
|
||||||
|
|
||||||
// typeLock must be held.
|
// 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;
|
var ok bool;
|
||||||
if enginePtr, ok = ignorerCache[wireId]; !ok {
|
if enginePtr, ok = ignorerCache[wireId]; !ok {
|
||||||
// To handle recursive types, mark this engine as underway before compiling.
|
// 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
|
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.
|
// Dereference down to the underlying object.
|
||||||
rt, indir := indirect(reflect.Typeof(e));
|
rt, indir := indirect(reflect.Typeof(e));
|
||||||
v := reflect.NewValue(e);
|
v := reflect.NewValue(e);
|
||||||
|
|
|
||||||
|
|
@ -13,27 +13,30 @@ import (
|
||||||
"sync";
|
"sync";
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A Decoder manages the receipt of type and data information read from the
|
||||||
|
// remote side of a connection.
|
||||||
type Decoder struct {
|
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
|
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
|
state *decodeState; // reads data from in-memory buffer
|
||||||
countState *decodeState; // reads counts from wire
|
countState *decodeState; // reads counts from wire
|
||||||
buf []byte;
|
buf []byte;
|
||||||
oneByte []byte;
|
oneByte []byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder that reads from the io.Reader.
|
||||||
func NewDecoder(r io.Reader) *Decoder {
|
func NewDecoder(r io.Reader) *Decoder {
|
||||||
dec := new(Decoder);
|
dec := new(Decoder);
|
||||||
dec.r = r;
|
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.state = new(decodeState); // buffer set in Decode(); rest is unimportant
|
||||||
dec.oneByte = make([]byte, 1);
|
dec.oneByte = make([]byte, 1);
|
||||||
|
|
||||||
return dec;
|
return dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dec *Decoder) recvType(id TypeId) {
|
func (dec *Decoder) recvType(id typeId) {
|
||||||
// Have we already seen this type? That's an error
|
// Have we already seen this type? That's an error
|
||||||
if wt_, alreadySeen := dec.seen[id]; alreadySeen {
|
if wt_, alreadySeen := dec.seen[id]; alreadySeen {
|
||||||
dec.state.err = os.ErrorString("gob: duplicate type received");
|
dec.state.err = os.ErrorString("gob: duplicate type received");
|
||||||
|
|
@ -47,14 +50,16 @@ func (dec *Decoder) recvType(id TypeId) {
|
||||||
dec.seen[id] = wire;
|
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
|
// 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 {
|
func (dec *Decoder) Decode(e interface{}) os.Error {
|
||||||
rt, indir := indirect(reflect.Typeof(e));
|
rt, indir := indirect(reflect.Typeof(e));
|
||||||
|
|
||||||
// Make sure we're single-threaded through here.
|
// Make sure we're single-threaded through here.
|
||||||
dec.Lock();
|
dec.mutex.Lock();
|
||||||
defer dec.Unlock();
|
defer dec.mutex.Unlock();
|
||||||
|
|
||||||
dec.state.err = nil;
|
dec.state.err = nil;
|
||||||
for {
|
for {
|
||||||
|
|
@ -81,7 +86,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a type id.
|
// Receive a type id.
|
||||||
id := TypeId(decodeInt(dec.state));
|
id := typeId(decodeInt(dec.state));
|
||||||
if dec.state.err != nil {
|
if dec.state.err != nil {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,183 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// 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
|
package gob
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -13,19 +190,22 @@ import (
|
||||||
"sync";
|
"sync";
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// An Encoder manages the transmission of type and data information to the
|
||||||
|
// other side of a connection.
|
||||||
type Encoder struct {
|
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
|
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
|
state *encoderState; // so we can encode integers, strings directly
|
||||||
countState *encoderState; // stage for writing counts
|
countState *encoderState; // stage for writing counts
|
||||||
buf []byte; // for collecting the output.
|
buf []byte; // for collecting the output.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new encoder that will transmit on the io.Writer.
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
enc := new(Encoder);
|
enc := new(Encoder);
|
||||||
enc.w = w;
|
enc.w = w;
|
||||||
enc.sent = make(map[reflect.Type] TypeId);
|
enc.sent = make(map[reflect.Type] typeId);
|
||||||
enc.state = new(encoderState);
|
enc.state = new(encoderState);
|
||||||
enc.state.b = new(bytes.Buffer); // the rest isn't important; all we need is buffer and writer
|
enc.state.b = new(bytes.Buffer); // the rest isn't important; all we need is buffer and writer
|
||||||
enc.countState = new(encoderState);
|
enc.countState = new(encoderState);
|
||||||
|
|
@ -91,15 +271,15 @@ func (enc *Encoder) sendType(origt reflect.Type) {
|
||||||
typeLock.Unlock();
|
typeLock.Unlock();
|
||||||
// Send the pair (-id, type)
|
// Send the pair (-id, type)
|
||||||
// Id:
|
// Id:
|
||||||
encodeInt(enc.state, -int64(info.typeId));
|
encodeInt(enc.state, -int64(info.id));
|
||||||
// Type:
|
// Type:
|
||||||
encode(enc.state.b, info.wire);
|
encode(enc.state.b, info.wire);
|
||||||
enc.send();
|
enc.send();
|
||||||
|
|
||||||
// Remember we've sent this type.
|
// 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.
|
// 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
|
// Now send the inner types
|
||||||
st := rt.(*reflect.StructType);
|
st := rt.(*reflect.StructType);
|
||||||
for i := 0; i < st.NumField(); i++ {
|
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 {
|
func (enc *Encoder) Encode(e interface{}) os.Error {
|
||||||
if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
|
if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
|
||||||
panicln("Encoder: buffer not empty")
|
panicln("Encoder: buffer not empty")
|
||||||
|
|
@ -114,8 +296,8 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
|
||||||
rt, indir := indirect(reflect.Typeof(e));
|
rt, indir := indirect(reflect.Typeof(e));
|
||||||
|
|
||||||
// Make sure we're single-threaded through here.
|
// Make sure we're single-threaded through here.
|
||||||
enc.Lock();
|
enc.mutex.Lock();
|
||||||
defer enc.Unlock();
|
defer enc.mutex.Unlock();
|
||||||
|
|
||||||
// Make sure the type is known to the other side.
|
// Make sure the type is known to the other side.
|
||||||
// First, have we already sent this type?
|
// First, have we already sent this type?
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func TestBasicEncoder(t *testing.T) {
|
||||||
t.Fatal("error decoding ET1 type:", err);
|
t.Fatal("error decoding ET1 type:", err);
|
||||||
}
|
}
|
||||||
info := getTypeInfo(reflect.Typeof(ET1{}));
|
info := getTypeInfo(reflect.Typeof(ET1{}));
|
||||||
trueWire1 := &wireType{s: info.typeId.gobType().(*structType)};
|
trueWire1 := &wireType{s: info.id.gobType().(*structType)};
|
||||||
if !reflect.DeepEqual(wire1, trueWire1) {
|
if !reflect.DeepEqual(wire1, trueWire1) {
|
||||||
t.Fatalf("invalid wireType for ET1: expected %+v; got %+v\n", *trueWire1, *wire1);
|
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);
|
t.Fatal("error decoding ET2 type:", err);
|
||||||
}
|
}
|
||||||
info = getTypeInfo(reflect.Typeof(ET2{}));
|
info = getTypeInfo(reflect.Typeof(ET2{}));
|
||||||
trueWire2 := &wireType{s: info.typeId.gobType().(*structType)};
|
trueWire2 := &wireType{s: info.id.gobType().(*structType)};
|
||||||
if !reflect.DeepEqual(wire2, trueWire2) {
|
if !reflect.DeepEqual(wire2, trueWire2) {
|
||||||
t.Fatalf("invalid wireType for ET2: expected %+v; got %+v\n", *trueWire2, *wire2);
|
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
|
// 8) The value of et1
|
||||||
newEt1 := new(ET1);
|
newEt1 := new(ET1);
|
||||||
et1Id := getTypeInfo(reflect.Typeof(*newEt1)).typeId;
|
et1Id := getTypeInfo(reflect.Typeof(*newEt1)).id;
|
||||||
err = decode(b, et1Id, newEt1);
|
err = decode(b, et1Id, newEt1);
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error decoding ET1 value:", err);
|
t.Fatal("error decoding ET1 value:", err);
|
||||||
|
|
|
||||||
|
|
@ -13,23 +13,23 @@ import (
|
||||||
"unicode";
|
"unicode";
|
||||||
)
|
)
|
||||||
|
|
||||||
// Types are identified by an integer TypeId. These can be passed on the wire.
|
// A typeId represents a gob Type as an integer that can be passed on the wire.
|
||||||
// Internally, they are used as keys to a map to recover the underlying type info.
|
// Internally, typeIds are used as keys to a map to recover the underlying type info.
|
||||||
type TypeId int32
|
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
|
var typeLock sync.Mutex // set while building a type
|
||||||
|
|
||||||
type gobType interface {
|
type gobType interface {
|
||||||
id() TypeId;
|
id() typeId;
|
||||||
setId(id TypeId);
|
setId(id typeId);
|
||||||
Name() string;
|
Name() string;
|
||||||
String() string;
|
String() string;
|
||||||
safeString(seen map[TypeId] bool) string;
|
safeString(seen map[typeId] bool) string;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = make(map[reflect.Type] gobType)
|
var types = make(map[reflect.Type] gobType)
|
||||||
var idToType = make(map[TypeId] gobType)
|
var idToType = make(map[typeId] gobType)
|
||||||
|
|
||||||
func setTypeId(typ gobType) {
|
func setTypeId(typ gobType) {
|
||||||
nextId++;
|
nextId++;
|
||||||
|
|
@ -37,32 +37,34 @@ func setTypeId(typ gobType) {
|
||||||
idToType[nextId] = typ;
|
idToType[nextId] = typ;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t TypeId) gobType() gobType {
|
func (t typeId) gobType() gobType {
|
||||||
if t == 0 {
|
if t == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return idToType[t]
|
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()
|
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()
|
return t.gobType().Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common elements of all types.
|
// Common elements of all types.
|
||||||
type commonType struct {
|
type commonType struct {
|
||||||
name string;
|
name string;
|
||||||
_id TypeId;
|
_id typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *commonType) id() TypeId {
|
func (t *commonType) id() typeId {
|
||||||
return t._id
|
return t._id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *commonType) setId(id TypeId) {
|
func (t *commonType) setId(id typeId) {
|
||||||
t._id = id
|
t._id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,20 +81,20 @@ func (t *commonType) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic type identifiers, predefined.
|
// Basic type identifiers, predefined.
|
||||||
var tBool TypeId
|
var tBool typeId
|
||||||
var tInt TypeId
|
var tInt typeId
|
||||||
var tUint TypeId
|
var tUint typeId
|
||||||
var tFloat TypeId
|
var tFloat typeId
|
||||||
var tString TypeId
|
var tString typeId
|
||||||
var tBytes TypeId
|
var tBytes typeId
|
||||||
|
|
||||||
// Predefined because it's needed by the Decoder
|
// Predefined because it's needed by the Decoder
|
||||||
var tWireType TypeId
|
var tWireType typeId
|
||||||
|
|
||||||
// Array type
|
// Array type
|
||||||
type arrayType struct {
|
type arrayType struct {
|
||||||
commonType;
|
commonType;
|
||||||
Elem TypeId;
|
Elem typeId;
|
||||||
Len int;
|
Len int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +104,7 @@ func newArrayType(name string, elem gobType, length int) *arrayType {
|
||||||
return a;
|
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 {
|
if _, ok := seen[a._id]; ok {
|
||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +119,7 @@ func (a *arrayType) String() string {
|
||||||
// Slice type
|
// Slice type
|
||||||
type sliceType struct {
|
type sliceType struct {
|
||||||
commonType;
|
commonType;
|
||||||
Elem TypeId;
|
Elem typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSliceType(name string, elem gobType) *sliceType {
|
func newSliceType(name string, elem gobType) *sliceType {
|
||||||
|
|
@ -126,7 +128,7 @@ func newSliceType(name string, elem gobType) *sliceType {
|
||||||
return s;
|
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 {
|
if _, ok := seen[s._id]; ok {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
@ -135,13 +137,13 @@ func (s *sliceType) safeString(seen map[TypeId] bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sliceType) String() string {
|
func (s *sliceType) String() string {
|
||||||
return s.safeString(make(map[TypeId] bool))
|
return s.safeString(make(map[typeId] bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct type
|
// Struct type
|
||||||
type fieldType struct {
|
type fieldType struct {
|
||||||
name string;
|
name string;
|
||||||
typeId TypeId;
|
id typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
type structType struct {
|
type structType struct {
|
||||||
|
|
@ -149,7 +151,7 @@ type structType struct {
|
||||||
field []*fieldType;
|
field []*fieldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *structType) safeString(seen map[TypeId] bool) string {
|
func (s *structType) safeString(seen map[typeId] bool) string {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
}
|
}
|
||||||
|
|
@ -159,14 +161,14 @@ func (s *structType) safeString(seen map[TypeId] bool) string {
|
||||||
seen[s._id] = true;
|
seen[s._id] = true;
|
||||||
str := s.name + " = struct { ";
|
str := s.name + " = struct { ";
|
||||||
for _, f := range s.field {
|
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 += "}";
|
str += "}";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *structType) String() string {
|
func (s *structType) String() string {
|
||||||
return s.safeString(make(map[TypeId] bool))
|
return s.safeString(make(map[typeId] bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStructType(name string) *structType {
|
func newStructType(name string) *structType {
|
||||||
|
|
@ -294,8 +296,14 @@ func getType(name string, rt reflect.Type) gobType {
|
||||||
return t;
|
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()
|
// 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);
|
rt := reflect.Typeof(e);
|
||||||
_, present := types[rt];
|
_, present := types[rt];
|
||||||
if present {
|
if present {
|
||||||
|
|
@ -304,6 +312,7 @@ func bootstrapType(name string, e interface{}) TypeId {
|
||||||
typ := &commonType{ name: name };
|
typ := &commonType{ name: name };
|
||||||
types[rt] = typ;
|
types[rt] = typ;
|
||||||
setTypeId(typ);
|
setTypeId(typ);
|
||||||
|
checkId(expect, nextId);
|
||||||
return nextId
|
return nextId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,7 +338,7 @@ func (w *wireType) name() string {
|
||||||
type decEngine struct // defined in decode.go
|
type decEngine struct // defined in decode.go
|
||||||
type encEngine struct // defined in encode.go
|
type encEngine struct // defined in encode.go
|
||||||
type typeInfo struct {
|
type typeInfo struct {
|
||||||
typeId TypeId;
|
id typeId;
|
||||||
encoder *encEngine;
|
encoder *encEngine;
|
||||||
wire *wireType;
|
wire *wireType;
|
||||||
}
|
}
|
||||||
|
|
@ -346,21 +355,26 @@ func getTypeInfo(rt reflect.Type) *typeInfo {
|
||||||
if !ok {
|
if !ok {
|
||||||
info = new(typeInfo);
|
info = new(typeInfo);
|
||||||
name := rt.Name();
|
name := rt.Name();
|
||||||
info.typeId = getType(name, rt).id();
|
info.id = getType(name, rt).id();
|
||||||
// assume it's a struct type
|
// assume it's a struct type
|
||||||
info.wire = &wireType{info.typeId.gobType().(*structType)};
|
info.wire = &wireType{info.id.gobType().(*structType)};
|
||||||
typeInfoMap[rt] = info;
|
typeInfoMap[rt] = info;
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
tBool = bootstrapType("bool", false);
|
// Create and check predefined types
|
||||||
tInt = bootstrapType("int", int(0));
|
tBool = bootstrapType("bool", false, 1);
|
||||||
tUint = bootstrapType("uint", uint(0));
|
tInt = bootstrapType("int", int(0), 2);
|
||||||
tFloat = bootstrapType("float", float64(0));
|
tUint = bootstrapType("uint", uint(0), 3);
|
||||||
|
tFloat = bootstrapType("float", float64(0), 4);
|
||||||
// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
|
// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
|
||||||
tBytes = bootstrapType("bytes", make([]byte, 0));
|
tBytes = bootstrapType("bytes", make([]byte, 0), 5);
|
||||||
tString= bootstrapType("string", "");
|
tString= bootstrapType("string", "", 6);
|
||||||
tWireType = getTypeInfo(reflect.Typeof(wireType{})).typeId;
|
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 {
|
type typeT struct {
|
||||||
typeId TypeId;
|
id typeId;
|
||||||
str string;
|
str string;
|
||||||
}
|
}
|
||||||
var basicTypes = []typeT {
|
var basicTypes = []typeT {
|
||||||
|
|
@ -33,10 +33,10 @@ func getTypeUnlocked(name string, rt reflect.Type) gobType {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
for _, tt := range basicTypes {
|
for _, tt := range basicTypes {
|
||||||
if tt.typeId.String() != tt.str {
|
if tt.id.String() != tt.str {
|
||||||
t.Errorf("checkType: expected %q got %s", tt.str, tt.typeId.String())
|
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)
|
t.Errorf("id for %q is zero", tt.str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue