| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package gob | |
| import ( | |
| "fmt" | |
| "os" | |
| "reflect" | |
| "sync" | |
| ) | |
| // Reflection types are themselves interface values holding structs | |
| // describing the type. Each type has a different struct so that struct can | |
| // be the kind. For example, if typ is the reflect type for an int8, typ is | |
| // a pointer to a reflect.Int8Type struct; if typ is the reflect type for a | |
| // function, typ is a pointer to a reflect.FuncType struct; we use the type | |
| // of that pointer as the kind. | |
| // 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 typeLock sync.Mutex // set while building a type | |
| const firstUserId = 64 // lowest id number granted to user | |
| type gobType interface { | |
| id() typeId | |
| setId(id typeId) | |
| Name() string | |
| string() string // not public; only for debugging | |
| safeString(seen map[typeId]bool) string | |
| } | |
| var types = make(map[reflect.Type]gobType) | |
| var idToType = make(map[typeId]gobType) | |
| var builtinIdToType map[typeId]gobType // set in init() after builtins are established | |
| func setTypeId(typ gobType) { | |
| nextId++ | |
| typ.setId(nextId) | |
| idToType[nextId] = typ | |
| } | |
| func (t typeId) gobType() gobType { | |
| if t == 0 { | |
| return nil | |
| } | |
| return idToType[t] | |
| } | |
| // string returns the string representation of the type associated with the typeId. | |
| func (t typeId) string() string { return t.gobType().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 | |
| } | |
| func (t *commonType) id() typeId { return t._id } | |
| func (t *commonType) setId(id typeId) { t._id = id } | |
| func (t *commonType) string() string { return t.name } | |
| func (t *commonType) safeString(seen map[typeId]bool) string { | |
| return t.name | |
| } | |
| func (t *commonType) Name() string { return t.name } | |
| // Create and check predefined types | |
| // The string for tBytes is "bytes" not "[]byte" to signify its specialness. | |
| var tBool = bootstrapType("bool", false, 1) | |
| var tInt = bootstrapType("int", int(0), 2) | |
| var tUint = bootstrapType("uint", uint(0), 3) | |
| var tFloat = bootstrapType("float", float64(0), 4) | |
| var tBytes = bootstrapType("bytes", make([]byte, 0), 5) | |
| var tString = bootstrapType("string", "", 6) | |
| // Predefined because it's needed by the Decoder | |
| var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id | |
| func init() { | |
| // Some magic numbers to make sure there are no surprises. | |
| checkId(7, tWireType) | |
| checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id) | |
| checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id) | |
| checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id) | |
| builtinIdToType = make(map[typeId]gobType) | |
| for k, v := range idToType { | |
| builtinIdToType[k] = v | |
| } | |
| // Move the id space upwards to allow for growth in the predefined world | |
| // without breaking existing files. | |
| if nextId > firstUserId { | |
| panic(fmt.Sprintln("nextId too large:", nextId)) | |
| } | |
| nextId = firstUserId | |
| } | |
| // Array type | |
| type arrayType struct { | |
| commonType | |
| Elem typeId | |
| Len int | |
| } | |
| func newArrayType(name string, elem gobType, length int) *arrayType { | |
| a := &arrayType{commonType{name: name}, elem.id(), length} | |
| setTypeId(a) | |
| return a | |
| } | |
| func (a *arrayType) safeString(seen map[typeId]bool) string { | |
| if seen[a._id] { | |
| return a.name | |
| } | |
| seen[a._id] = true | |
| return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen)) | |
| } | |
| func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) } | |
| // Map type | |
| type mapType struct { | |
| commonType | |
| Key typeId | |
| Elem typeId | |
| } | |
| func newMapType(name string, key, elem gobType) *mapType { | |
| m := &mapType{commonType{name: name}, key.id(), elem.id()} | |
| setTypeId(m) | |
| return m | |
| } | |
| func (m *mapType) safeString(seen map[typeId]bool) string { | |
| if seen[m._id] { | |
| return m.name | |
| } | |
| seen[m._id] = true | |
| key := m.Key.gobType().safeString(seen) | |
| elem := m.Elem.gobType().safeString(seen) | |
| return fmt.Sprintf("map[%s]%s", key, elem) | |
| } | |
| func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) } | |
| // Slice type | |
| type sliceType struct { | |
| commonType | |
| Elem typeId | |
| } | |
| func newSliceType(name string, elem gobType) *sliceType { | |
| s := &sliceType{commonType{name: name}, elem.id()} | |
| setTypeId(s) | |
| return s | |
| } | |
| func (s *sliceType) safeString(seen map[typeId]bool) string { | |
| if seen[s._id] { | |
| return s.name | |
| } | |
| seen[s._id] = true | |
| return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen)) | |
| } | |
| func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) } | |
| // Struct type | |
| type fieldType struct { | |
| name string | |
| id typeId | |
| } | |
| type structType struct { | |
| commonType | |
| field []*fieldType | |
| } | |
| func (s *structType) safeString(seen map[typeId]bool) string { | |
| if s == nil { | |
| return "<nil>" | |
| } | |
| if _, ok := seen[s._id]; ok { | |
| return s.name | |
| } | |
| seen[s._id] = true | |
| str := s.name + " = struct { " | |
| for _, f := range s.field { | |
| 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)) } | |
| func newStructType(name string) *structType { | |
| s := &structType{commonType{name: name}, nil} | |
| setTypeId(s) | |
| return s | |
| } | |
| // Step through the indirections on a type to discover the base type. | |
| // Return the number of indirections. | |
| func indirect(t reflect.Type) (rt reflect.Type, count int) { | |
| rt = t | |
| for { | |
| pt, ok := rt.(*reflect.PtrType) | |
| if !ok { | |
| break | |
| } | |
| rt = pt.Elem() | |
| count++ | |
| } | |
| return | |
| } | |
| func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) { | |
| switch t := rt.(type) { | |
| // All basic types are easy: they are predefined. | |
| case *reflect.BoolType: | |
| return tBool.gobType(), nil | |
| case *reflect.IntType: | |
| return tInt.gobType(), nil | |
| case *reflect.UintType: | |
| return tUint.gobType(), nil | |
| case *reflect.FloatType: | |
| return tFloat.gobType(), nil | |
| case *reflect.StringType: | |
| return tString.gobType(), nil | |
| case *reflect.ArrayType: | |
| gt, err := getType("", t.Elem()) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return newArrayType(name, gt, t.Len()), nil | |
| case *reflect.MapType: | |
| kt, err := getType("", t.Key()) | |
| if err != nil { | |
| return nil, err | |
| } | |
| vt, err := getType("", t.Elem()) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return newMapType(name, kt, vt), nil | |
| case *reflect.SliceType: | |
| // []byte == []uint8 is a special case | |
| if t.Elem().Kind() == reflect.Uint8 { | |
| return tBytes.gobType(), nil | |
| } | |
| gt, err := getType(t.Elem().Name(), t.Elem()) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return newSliceType(name, gt), nil | |
| case *reflect.StructType: | |
| // Install the struct type itself before the fields so recursive | |
| // structures can be constructed safely. | |
| strType := newStructType(name) | |
| types[rt] = strType | |
| idToType[strType.id()] = strType | |
| field := make([]*fieldType, t.NumField()) | |
| for i := 0; i < t.NumField(); i++ { | |
| f := t.Field(i) | |
| typ, _ := indirect(f.Type) | |
| tname := typ.Name() | |
| if tname == "" { | |
| tname = f.Type.String() | |
| } | |
| gt, err := getType(tname, f.Type) | |
| if err != nil { | |
| return nil, err | |
| } | |
| field[i] = &fieldType{f.Name, gt.id()} | |
| } | |
| strType.field = field | |
| return strType, nil | |
| default: | |
| return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String()) | |
| } | |
| return nil, nil | |
| } | |
| // getType returns the Gob type describing the given reflect.Type. | |
| // typeLock must be held. | |
| func getType(name string, rt reflect.Type) (gobType, os.Error) { | |
| // Flatten the data structure by collapsing out pointers | |
| for { | |
| pt, ok := rt.(*reflect.PtrType) | |
| if !ok { | |
| break | |
| } | |
| rt = pt.Elem() | |
| } | |
| typ, present := types[rt] | |
| if present { | |
| return typ, nil | |
| } | |
| typ, err := newTypeObject(name, rt) | |
| if err == nil { | |
| types[rt] = typ | |
| } | |
| return typ, err | |
| } | |
| func checkId(want, got typeId) { | |
| if want != got { | |
| panic("bootstrap type wrong id: " + got.Name() + " " + got.string() + " not " + want.string()) | |
| } | |
| } | |
| // used for building the basic types; called only from init() | |
| func bootstrapType(name string, e interface{}, expect typeId) typeId { | |
| rt := reflect.Typeof(e) | |
| _, present := types[rt] | |
| if present { | |
| panic("bootstrap type already present: " + name) | |
| } | |
| typ := &commonType{name: name} | |
| types[rt] = typ | |
| setTypeId(typ) | |
| checkId(expect, nextId) | |
| return nextId | |
| } | |
| // Representation of the information we send and receive about this type. | |
| // Each value we send is preceded by its type definition: an encoded int. | |
| // However, the very first time we send the value, we first send the pair | |
| // (-id, wireType). | |
| // For bootstrapping purposes, we assume that the recipient knows how | |
| // to decode a wireType; it is exactly the wireType struct here, interpreted | |
| // using the gob rules for sending a structure, except that we assume the | |
| // ids for wireType and structType are known. The relevant pieces | |
| // are built in encode.go's init() function. | |
| // To maintain binary compatibility, if you extend this type, always put | |
| // the new fields last. | |
| type wireType struct { | |
| arrayT *arrayType | |
| sliceT *sliceType | |
| structT *structType | |
| mapT *mapType | |
| } | |
| func (w *wireType) name() string { | |
| if w.structT != nil { | |
| return w.structT.name | |
| } | |
| return "unknown" | |
| } | |
| type typeInfo struct { | |
| id typeId | |
| encoder *encEngine | |
| wire *wireType | |
| } | |
| var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock | |
| // The reflection type must have all its indirections processed out. | |
| // typeLock must be held. | |
| func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) { | |
| if _, ok := rt.(*reflect.PtrType); ok { | |
| panic("pointer type in getTypeInfo: " + rt.String()) | |
| } | |
| info, ok := typeInfoMap[rt] | |
| if !ok { | |
| info = new(typeInfo) | |
| name := rt.Name() | |
| gt, err := getType(name, rt) | |
| if err != nil { | |
| return nil, err | |
| } | |
| info.id = gt.id() | |
| t := info.id.gobType() | |
| switch typ := rt.(type) { | |
| case *reflect.ArrayType: | |
| info.wire = &wireType{arrayT: t.(*arrayType)} | |
| case *reflect.MapType: | |
| info.wire = &wireType{mapT: t.(*mapType)} | |
| case *reflect.SliceType: | |
| // []byte == []uint8 is a special case handled separately | |
| if typ.Elem().Kind() != reflect.Uint8 { | |
| info.wire = &wireType{sliceT: t.(*sliceType)} | |
| } | |
| case *reflect.StructType: | |
| info.wire = &wireType{structT: t.(*structType)} | |
| } | |
| typeInfoMap[rt] = info | |
| } | |
| return info, nil | |
| } | |
| // Called only when a panic is acceptable and unexpected. | |
| func mustGetTypeInfo(rt reflect.Type) *typeInfo { | |
| t, err := getTypeInfo(rt) | |
| if err != nil { | |
| panic("getTypeInfo: " + err.String()) | |
| } | |
| return t | |
| } |