summaryrefslogtreecommitdiff
path: root/libgo/go/gob/type.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/gob/type.go')
-rw-r--r--libgo/go/gob/type.go539
1 files changed, 539 insertions, 0 deletions
diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go
new file mode 100644
index 000000000..22502a6e6
--- /dev/null
+++ b/libgo/go/gob/type.go
@@ -0,0 +1,539 @@
+// 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", 0.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) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
+ }
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.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())
+ }
+ // Store the name and type provided by the user....
+ nameToConcreteType[name] = reflect.Typeof(value)
+ // but the flattened type in the type table, since that's what decode needs.
+ 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(float32(0))
+ Register(0.0)
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}