package gob
import (
)
type userTypeInfo struct {
user reflect.Type
base reflect.Type
indir int
externalEnc int
externalDec int
encIndir int8
decIndir int8
}
const (
xGob = 1 + iota
xBinary
xText
)
var userTypeCache sync.Map
func ( reflect.Type) (*userTypeInfo, error) {
if , := userTypeCache.Load(); {
return .(*userTypeInfo), nil
}
:= new(userTypeInfo)
.base =
.user =
:= .base
for {
:= .base
if .Kind() != reflect.Ptr {
break
}
.base = .Elem()
if .base == {
return nil, errors.New("can't represent recursive pointer type " + .base.String())
}
if .indir%2 == 0 {
= .Elem()
}
.indir++
}
if , := implementsInterface(.user, gobEncoderInterfaceType); {
.externalEnc, .encIndir = xGob,
} else if , := implementsInterface(.user, binaryMarshalerInterfaceType); {
.externalEnc, .encIndir = xBinary,
}
if , := implementsInterface(.user, gobDecoderInterfaceType); {
.externalDec, .decIndir = xGob,
} else if , := implementsInterface(.user, binaryUnmarshalerInterfaceType); {
.externalDec, .decIndir = xBinary,
}
, := userTypeCache.LoadOrStore(, )
return .(*userTypeInfo), nil
}
var (
gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem()
gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem()
binaryMarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
binaryUnmarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
textMarshalerInterfaceType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
textUnmarshalerInterfaceType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)
func (, reflect.Type) ( bool, int8) {
if == nil {
return
}
:=
for {
if .Implements() {
return true,
}
if := ; .Kind() == reflect.Ptr {
++
if > 100 {
return false, 0
}
= .Elem()
continue
}
break
}
if .Kind() != reflect.Ptr {
if reflect.PtrTo().Implements() {
return true, -1
}
}
return false, 0
}
func ( reflect.Type) *userTypeInfo {
, := validUserType()
if != nil {
error_()
}
return
}
type typeId int32
var nextId typeId
var typeLock sync.Mutex
const firstUserId = 64
type gobType interface {
id() typeId
setId(id typeId)
name() string
string() string
safeString(seen map[typeId]bool) string
}
var types = make(map[reflect.Type]gobType)
var idToType = make(map[typeId]gobType)
var builtinIdToType map[typeId]gobType
func ( gobType) {
if .id() != 0 {
return
}
nextId++
.setId(nextId)
idToType[nextId] =
}
func ( typeId) () gobType {
if == 0 {
return nil
}
return idToType[]
}
func ( typeId) () string {
if .gobType() == nil {
return "<nil>"
}
return .gobType().string()
}
func ( typeId) () string {
if .gobType() == nil {
return "<nil>"
}
return .gobType().name()
}
type CommonType struct {
Name string
Id typeId
}
func ( *CommonType) () typeId { return .Id }
func ( *CommonType) ( typeId) { .Id = }
func ( *CommonType) () string { return .Name }
func ( *CommonType) ( map[typeId]bool) string {
return .Name
}
func ( *CommonType) () string { return .Name }
var (
tBool = bootstrapType("bool", (*bool)(nil), 1)
tInt = bootstrapType("int", (*int)(nil), 2)
tUint = bootstrapType("uint", (*uint)(nil), 3)
tFloat = bootstrapType("float", (*float64)(nil), 4)
tBytes = bootstrapType("bytes", (*[]byte)(nil), 5)
tString = bootstrapType("string", (*string)(nil), 6)
tComplex = bootstrapType("complex", (*complex128)(nil), 7)
tInterface = bootstrapType("interface", (*interface{})(nil), 8)
tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil), 9)
tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil), 10)
tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil), 11)
tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil), 12)
tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil), 13)
tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil), 14)
tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil), 15)
)
var tWireType = mustGetTypeInfo(reflect.TypeOf(wireType{})).id
var wireTypeUserInfo *userTypeInfo
func () {
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 , := range idToType {
builtinIdToType[] =
}
if nextId > firstUserId {
panic(fmt.Sprintln("nextId too large:", nextId))
}
nextId = firstUserId
registerBasics()
wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
}
type arrayType struct {
CommonType
Elem typeId
Len int
}
func ( string) *arrayType {
:= &arrayType{CommonType{Name: }, 0, 0}
return
}
func ( *arrayType) ( gobType, int) {
setTypeId()
.Elem = .id()
.Len =
}
func ( *arrayType) ( map[typeId]bool) string {
if [.Id] {
return .Name
}
[.Id] = true
return fmt.Sprintf("[%d]%s", .Len, .Elem.gobType().safeString())
}
func ( *arrayType) () string { return .safeString(make(map[typeId]bool)) }
type gobEncoderType struct {
CommonType
}
func ( string) *gobEncoderType {
:= &gobEncoderType{CommonType{Name: }}
setTypeId()
return
}
func ( *gobEncoderType) ( map[typeId]bool) string {
return .Name
}
func ( *gobEncoderType) () string { return .Name }
type mapType struct {
CommonType
Key typeId
Elem typeId
}
func ( string) *mapType {
:= &mapType{CommonType{Name: }, 0, 0}
return
}
func ( *mapType) (, gobType) {
setTypeId()
.Key = .id()
.Elem = .id()
}
func ( *mapType) ( map[typeId]bool) string {
if [.Id] {
return .Name
}
[.Id] = true
:= .Key.gobType().safeString()
:= .Elem.gobType().safeString()
return fmt.Sprintf("map[%s]%s", , )
}
func ( *mapType) () string { return .safeString(make(map[typeId]bool)) }
type sliceType struct {
CommonType
Elem typeId
}
func ( string) *sliceType {
:= &sliceType{CommonType{Name: }, 0}
return
}
func ( *sliceType) ( gobType) {
setTypeId()
if .id() == 0 {
setTypeId()
}
.Elem = .id()
}
func ( *sliceType) ( map[typeId]bool) string {
if [.Id] {
return .Name
}
[.Id] = true
return fmt.Sprintf("[]%s", .Elem.gobType().safeString())
}
func ( *sliceType) () string { return .safeString(make(map[typeId]bool)) }
type fieldType struct {
Name string
Id typeId
}
type structType struct {
CommonType
Field []*fieldType
}
func ( *structType) ( map[typeId]bool) string {
if == nil {
return "<nil>"
}
if , := [.Id]; {
return .Name
}
[.Id] = true
:= .Name + " = struct { "
for , := range .Field {
+= fmt.Sprintf("%s %s; ", .Name, .Id.gobType().safeString())
}
+= "}"
return
}
func ( *structType) () string { return .safeString(make(map[typeId]bool)) }
func ( string) *structType {
:= &structType{CommonType{Name: }, nil}
setTypeId()
return
}
func ( string, *userTypeInfo, reflect.Type) (gobType, error) {
if .externalEnc != 0 {
return newGobEncoderType(), nil
}
var error
var , gobType
defer func() {
if != nil {
delete(types, )
}
}()
switch := ; .Kind() {
case reflect.Bool:
return tBool.gobType(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return tInt.gobType(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return tUint.gobType(), nil
case reflect.Float32, reflect.Float64:
return tFloat.gobType(), nil
case reflect.Complex64, reflect.Complex128:
return tComplex.gobType(), nil
case reflect.String:
return tString.gobType(), nil
case reflect.Interface:
return tInterface.gobType(), nil
case reflect.Array:
:= newArrayType()
types[] =
, = getBaseType("", .Elem())
if != nil {
return nil,
}
.init(, .Len())
return , nil
case reflect.Map:
:= newMapType()
types[] =
, = getBaseType("", .Key())
if != nil {
return nil,
}
, = getBaseType("", .Elem())
if != nil {
return nil,
}
.init(, )
return , nil
case reflect.Slice:
if .Elem().Kind() == reflect.Uint8 {
return tBytes.gobType(), nil
}
:= newSliceType()
types[] =
, = getBaseType(.Elem().Name(), .Elem())
if != nil {
return nil,
}
.init()
return , nil
case reflect.Struct:
:= newStructType()
types[] =
idToType[.id()] =
for := 0; < .NumField(); ++ {
:= .Field()
if !isSent(&) {
continue
}
:= userType(.Type).base
:= .Name()
if == "" {
:= userType(.Type).base
= .String()
}
, := getBaseType(, .Type)
if != nil {
return nil,
}
if .id() == 0 {
setTypeId()
}
.Field = append(.Field, &fieldType{.Name, .id()})
}
return , nil
default:
return nil, errors.New("gob NewTypeObject can't handle type: " + .String())
}
}
func ( string) bool {
, := utf8.DecodeRuneInString()
return unicode.IsUpper()
}
func ( *reflect.StructField) bool {
if !isExported(.Name) {
return false
}
:= .Type
for .Kind() == reflect.Ptr {
= .Elem()
}
if .Kind() == reflect.Chan || .Kind() == reflect.Func {
return false
}
return true
}
func ( string, reflect.Type) (gobType, error) {
:= userType()
return getType(, , .base)
}
func ( string, *userTypeInfo, reflect.Type) (gobType, error) {
, := types[]
if {
return , nil
}
, := newTypeObject(, , )
if == nil {
types[] =
}
return ,
}
func (, typeId) {
if != {
fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(), int())
panic("bootstrap type wrong id: " + .name() + " " + .string() + " not " + .string())
}
}
func ( string, interface{}, typeId) typeId {
:= reflect.TypeOf().Elem()
, := types[]
if {
panic("bootstrap type already present: " + + ", " + .String())
}
:= &CommonType{Name: }
types[] =
setTypeId()
checkId(, nextId)
userType()
return nextId
}
type wireType struct {
ArrayT *arrayType
SliceT *sliceType
StructT *structType
MapT *mapType
GobEncoderT *gobEncoderType
BinaryMarshalerT *gobEncoderType
TextMarshalerT *gobEncoderType
}
func ( *wireType) () string {
const = "unknown type"
if == nil {
return
}
switch {
case .ArrayT != nil:
return .ArrayT.Name
case .SliceT != nil:
return .SliceT.Name
case .StructT != nil:
return .StructT.Name
case .MapT != nil:
return .MapT.Name
case .GobEncoderT != nil:
return .GobEncoderT.Name
case .BinaryMarshalerT != nil:
return .BinaryMarshalerT.Name
case .TextMarshalerT != nil:
return .TextMarshalerT.Name
}
return
}
type typeInfo struct {
id typeId
encInit sync.Mutex
encoder atomic.Value
wire *wireType
}
var typeInfoMap atomic.Value
func ( reflect.Type) *typeInfo {
, := typeInfoMap.Load().(map[reflect.Type]*typeInfo)
return []
}
func ( *userTypeInfo) (*typeInfo, error) {
:= .base
if .externalEnc != 0 {
= .user
}
if := lookupTypeInfo(); != nil {
return , nil
}
return buildTypeInfo(, )
}
func ( *userTypeInfo, reflect.Type) (*typeInfo, error) {
typeLock.Lock()
defer typeLock.Unlock()
if := lookupTypeInfo(); != nil {
return , nil
}
, := getBaseType(.Name(), )
if != nil {
return nil,
}
:= &typeInfo{id: .id()}
if .externalEnc != 0 {
, := getType(.Name(), , )
if != nil {
return nil,
}
:= .id().gobType().(*gobEncoderType)
switch .externalEnc {
case xGob:
.wire = &wireType{GobEncoderT: }
case xBinary:
.wire = &wireType{BinaryMarshalerT: }
case xText:
.wire = &wireType{TextMarshalerT: }
}
= .user
} else {
:= .id.gobType()
switch := ; .Kind() {
case reflect.Array:
.wire = &wireType{ArrayT: .(*arrayType)}
case reflect.Map:
.wire = &wireType{MapT: .(*mapType)}
case reflect.Slice:
if .Elem().Kind() != reflect.Uint8 {
.wire = &wireType{SliceT: .(*sliceType)}
}
case reflect.Struct:
.wire = &wireType{StructT: .(*structType)}
}
}
:= make(map[reflect.Type]*typeInfo)
, := typeInfoMap.Load().(map[reflect.Type]*typeInfo)
for , := range {
[] =
}
[] =
typeInfoMap.Store()
return , nil
}
func ( reflect.Type) *typeInfo {
, := getTypeInfo(userType())
if != nil {
panic("getTypeInfo: " + .Error())
}
return
}
type GobEncoder interface {
GobEncode() ([]byte, error)
}
type GobDecoder interface {
GobDecode([]byte) error
}
var (
nameToConcreteType sync.Map
concreteTypeToName sync.Map
)
func ( string, interface{}) {
if == "" {
panic("attempt to register empty name")
}
:= userType(reflect.TypeOf())
if , := nameToConcreteType.LoadOrStore(, reflect.TypeOf()); && != .user {
panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", , , .user))
}
if , := concreteTypeToName.LoadOrStore(.base, ); && != {
nameToConcreteType.Delete()
panic(fmt.Sprintf("gob: registering duplicate names for %s: %q != %q", .user, , ))
}
}
func ( interface{}) {
:= reflect.TypeOf()
:= .String()
:= ""
if .Name() == "" {
if := ; .Kind() == reflect.Ptr {
= "*"
=
}
}
if .Name() != "" {
if .PkgPath() == "" {
= + .Name()
} else {
= + .PkgPath() + "." + .Name()
}
}
RegisterName(, )
}
func () {
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(float64(0))
Register(complex64(0i))
Register(complex128(0i))
Register(uintptr(0))
Register(false)
Register("")
Register([]byte(nil))
Register([]int(nil))
Register([]int8(nil))
Register([]int16(nil))
Register([]int32(nil))
Register([]int64(nil))
Register([]uint(nil))
Register([]uint8(nil))
Register([]uint16(nil))
Register([]uint32(nil))
Register([]uint64(nil))
Register([]float32(nil))
Register([]float64(nil))
Register([]complex64(nil))
Register([]complex128(nil))
Register([]uintptr(nil))
Register([]bool(nil))
Register([]string(nil))
}