blob: d68c8773cfdd86ecb969f6964fd636b3cc24f4b0 [file] [log] [blame]
// 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 {
if t.gobType() == nil {
return "<nil>"
}
return t.gobType().string()
}
// Name returns the name of the type associated with the typeId.
func (t typeId) Name() string {
if t.gobType() == nil {
return "<nil>"
}
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 (
// Primordial types, needed during initialization.
tBool = bootstrapType("bool", false, 1)
tInt = bootstrapType("int", int(0), 2)
tUint = bootstrapType("uint", uint(0), 3)
tFloat = bootstrapType("float", float64(0), 4)
tBytes = bootstrapType("bytes", make([]byte, 0), 5)
tString = bootstrapType("string", "", 6)
tComplex = bootstrapType("complex", 0+0i, 7)
tInterface = bootstrapType("interface", interface{}(nil), 8)
// Reserve some Ids for compatible expansion
tReserved7 = bootstrapType("_reserved1", struct{ r7 int }{}, 9)
tReserved6 = bootstrapType("_reserved1", struct{ r6 int }{}, 10)
tReserved5 = bootstrapType("_reserved1", struct{ r5 int }{}, 11)
tReserved4 = bootstrapType("_reserved1", struct{ r4 int }{}, 12)
tReserved3 = bootstrapType("_reserved1", struct{ r3 int }{}, 13)
tReserved2 = bootstrapType("_reserved1", struct{ r2 int }{}, 14)
tReserved1 = bootstrapType("_reserved1", struct{ r1 int }{}, 15)
)
// 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(16, tWireType)
checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
checkId(18, mustGetTypeInfo(reflect.Typeof(commonType{})).id)
checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).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
registerBasics()
}
// 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 base type and 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.ComplexType:
return tComplex.gobType(), nil
case *reflect.StringType:
return tString.gobType(), nil
case *reflect.InterfaceType:
return tInterface.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 == "" {
t, _ := indirect(f.Type)
tname = t.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) {
rt, _ = indirect(rt)
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 {
fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(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 + ", " + rt.String())
}
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 rt.Kind() == reflect.Ptr {
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
}
var (
nameToConcreteType = make(map[string]reflect.Type)
concreteTypeToName = make(map[reflect.Type]string)
)
// RegisterName is like Register but uses the provided name rather than the
// type's default.
func RegisterName(name string, value interface{}) {
if name == "" {
// reserved for nil
panic("attempt to register empty name")
}
rt, _ := indirect(reflect.Typeof(value))
// Check for incompatible duplicates.
if t, ok := nameToConcreteType[name]; ok && t != rt {
panic("gob: registering duplicate types for " + name)
}
if n, ok := concreteTypeToName[rt]; ok && n != name {
panic("gob: registering duplicate names for " + rt.String())
}
nameToConcreteType[name] = rt
concreteTypeToName[rt] = name
}
// Register records a type, identified by a value for that type, under its
// internal type name. That name will identify the concrete type of a value
// sent or received as an interface variable. Only types that will be
// transferred as implementations of interface values need to be registered.
// Expecting to be used only during initialization, it panics if the mapping
// between types and names is not a bijection.
func Register(value interface{}) {
// Default to printed representation for unnamed types
rt := reflect.Typeof(value)
name := rt.String()
// But for named types (or pointers to them), qualify with import path.
// Dereference one pointer looking for a named type.
star := ""
if rt.Name() == "" {
if pt, ok := rt.(*reflect.PtrType); ok {
star = "*"
rt = pt
}
}
if rt.Name() != "" {
if rt.PkgPath() == "" {
name = star + rt.Name()
} else {
name = star + rt.PkgPath() + "." + rt.Name()
}
}
RegisterName(name, value)
}
func registerBasics() {
Register(int(0))
Register(int8(0))
Register(int16(0))
Register(int32(0))
Register(int64(0))
Register(uint(0))
Register(uint8(0))
Register(uint16(0))
Register(uint32(0))
Register(uint64(0))
Register(float(0))
Register(float32(0))
Register(float64(0))
Register(complex(0i))
Register(complex64(0i))
Register(complex128(0i))
Register(false)
Register("")
Register([]byte(nil))
}