]> Cypherpunks repositories - gostls13.git/commitdiff
clean up for public use: make some stuff private, add doc comments.
authorRob Pike <r@golang.org>
Mon, 27 Jul 2009 18:02:06 +0000 (11:02 -0700)
committerRob Pike <r@golang.org>
Mon, 27 Jul 2009 18:02:06 +0000 (11:02 -0700)
R=rsc
DELTA=298  (202 added, 0 deleted, 96 changed)
OCL=32006
CL=32224

src/pkg/gob/codec_test.go
src/pkg/gob/decode.go
src/pkg/gob/decoder.go
src/pkg/gob/encoder.go
src/pkg/gob/encoder_test.go
src/pkg/gob/type.go
src/pkg/gob/type_test.go

index de2c5d6bc9a02e27c6299a205ed47d67fdd5e242..848a8719473fd160d1e671e05ca971a560a731b9 100644 (file)
@@ -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);
index 991b6f03f91907bab9ca659ca837a6ba89faf97e..a9148eb834a6488456e8d6e27fca1f2a95c90632 100644 (file)
@@ -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);
index 609a20484c6c37246a68b5ba4760357d808fde79..7dd99a0762331341339ef708f98a6b59f7cb1b5f 100644 (file)
@@ -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;
                }
index f75eccd958f54c008ca955e782951f8518cb350d..1182a70c4313b3b3dfaf5f3020296efaa2047473 100644 (file)
@@ -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?
index 4d9258345b1d1888f514947be0bcec4f21e58278..a7e66a57e39a9a0f9f13afc0c29334b3c4ad547f 100644 (file)
@@ -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);
index 006a0e442bca359d8af2b417402242e121c0a106..68d047ffd3fc29e3f2ce81e2fe177c3856a4f0ba 100644 (file)
@@ -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);
 }
index d190a3045e278f5d1d30d812a56d05d39e50a9fb..2f11ba3fea3518b0d8b48525d0fa7aab412a8400 100644 (file)
@@ -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)
                }
        }