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:
Rob Pike 2009-07-27 11:02:06 -07:00
parent 3ff5e727e2
commit 5aa174557a
7 changed files with 294 additions and 92 deletions

View 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);

View 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);

View 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;
}

View 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?

View 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);

View 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);
}

View 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)
}
}