// 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 ( // 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) // Types added to the language later, not needed during initialization. tComplex typeId ) // 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) // Complex was added after gob was written, so appears after the // fundamental types are built. tComplex = bootstrapType("complex", 0+0i, 15) decIgnoreOpMap[tComplex] = ignoreTwoUints 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 "" } 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.ComplexType: return tComplex.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 + ", " + 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 }