codekingpro/portable-devtools
114k
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package gob6 7import (8 "encoding"9 "errors"10 "fmt"11 "maps"12 "os"13 "reflect"14 "sync"15 "sync/atomic"16 "unicode"17 "unicode/utf8"18)19 20// userTypeInfo stores the information associated with a type the user has handed21// to the package. It's computed once and stored in a map keyed by reflection22// type.23type userTypeInfo struct {24 user reflect.Type // the type the user handed us25 base reflect.Type // the base type after all indirections26 indir int // number of indirections to reach the base type27 externalEnc int // xGob, xBinary, or xText28 externalDec int // xGob, xBinary, or xText29 encIndir int8 // number of indirections to reach the receiver type; may be negative30 decIndir int8 // number of indirections to reach the receiver type; may be negative31}32 33// externalEncoding bits34const (35 xGob = 1 + iota // GobEncoder or GobDecoder36 xBinary // encoding.BinaryMarshaler or encoding.BinaryUnmarshaler37 xText // encoding.TextMarshaler or encoding.TextUnmarshaler38)39 40var userTypeCache sync.Map // map[reflect.Type]*userTypeInfo41 42// validUserType returns, and saves, the information associated with user-provided type rt.43// If the user type is not valid, err will be non-nil. To be used when the error handler44// is not set up.45func validUserType(rt reflect.Type) (*userTypeInfo, error) {46 if ui, ok := userTypeCache.Load(rt); ok {47 return ui.(*userTypeInfo), nil48 }49 50 // Construct a new userTypeInfo and atomically add it to the userTypeCache.51 // If we lose the race, we'll waste a little CPU and create a little garbage52 // but return the existing value anyway.53 54 ut := new(userTypeInfo)55 ut.base = rt56 ut.user = rt57 // A type that is just a cycle of pointers (such as type T *T) cannot58 // be represented in gobs, which need some concrete data. We use a59 // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,60 // pp 539-540. As we step through indirections, run another type at61 // half speed. If they meet up, there's a cycle.62 slowpoke := ut.base // walks half as fast as ut.base63 for {64 pt := ut.base65 if pt.Kind() != reflect.Pointer {66 break67 }68 ut.base = pt.Elem()69 if ut.base == slowpoke { // ut.base lapped slowpoke70 // recursive pointer type.71 return nil, errors.New("can't represent recursive pointer type " + ut.base.String())72 }73 if ut.indir%2 == 0 {74 slowpoke = slowpoke.Elem()75 }76 ut.indir++77 }78 79 if ok, indir := implementsInterface(ut.user, gobEncoderInterfaceType); ok {80 ut.externalEnc, ut.encIndir = xGob, indir81 } else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok {82 ut.externalEnc, ut.encIndir = xBinary, indir83 }84 85 // NOTE(rsc): Would like to allow MarshalText here, but results in incompatibility86 // with older encodings for net.IP. See golang.org/issue/6760.87 // } else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {88 // ut.externalEnc, ut.encIndir = xText, indir89 // }90 91 if ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok {92 ut.externalDec, ut.decIndir = xGob, indir93 } else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok {94 ut.externalDec, ut.decIndir = xBinary, indir95 }96 97 // See note above.98 // } else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {99 // ut.externalDec, ut.decIndir = xText, indir100 // }101 102 ui, _ := userTypeCache.LoadOrStore(rt, ut)103 return ui.(*userTypeInfo), nil104}105 106var (107 gobEncoderInterfaceType = reflect.TypeFor[GobEncoder]()108 gobDecoderInterfaceType = reflect.TypeFor[GobDecoder]()109 binaryMarshalerInterfaceType = reflect.TypeFor[encoding.BinaryMarshaler]()110 binaryUnmarshalerInterfaceType = reflect.TypeFor[encoding.BinaryUnmarshaler]()111 textMarshalerInterfaceType = reflect.TypeFor[encoding.TextMarshaler]()112 textUnmarshalerInterfaceType = reflect.TypeFor[encoding.TextUnmarshaler]()113 114 wireTypeType = reflect.TypeFor[wireType]()115)116 117// implementsInterface reports whether the type implements the118// gobEncoder/gobDecoder interface.119// It also returns the number of indirections required to get to the120// implementation.121func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir int8) {122 if typ == nil {123 return124 }125 rt := typ126 // The type might be a pointer and we need to keep127 // dereferencing to the base type until we find an implementation.128 for {129 if rt.Implements(gobEncDecType) {130 return true, indir131 }132 if p := rt; p.Kind() == reflect.Pointer {133 indir++134 if indir > 100 { // insane number of indirections135 return false, 0136 }137 rt = p.Elem()138 continue139 }140 break141 }142 // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.143 if typ.Kind() != reflect.Pointer {144 // Not a pointer, but does the pointer work?145 if reflect.PointerTo(typ).Implements(gobEncDecType) {146 return true, -1147 }148 }149 return false, 0150}151 152// userType returns, and saves, the information associated with user-provided type rt.153// If the user type is not valid, it calls error.154func userType(rt reflect.Type) *userTypeInfo {155 ut, err := validUserType(rt)156 if err != nil {157 error_(err)158 }159 return ut160}161 162// A typeId represents a gob Type as an integer that can be passed on the wire.163// Internally, typeIds are used as keys to a map to recover the underlying type info.164type typeId int32165 166var typeLock sync.Mutex // set while building a type167const firstUserId = 64 // lowest id number granted to user168 169type gobType interface {170 id() typeId171 setId(id typeId)172 name() string173 string() string // not public; only for debugging174 safeString(seen map[typeId]bool) string175}176 177var (178 types = make(map[reflect.Type]gobType, 32)179 idToTypeSlice = make([]gobType, 1, firstUserId)180 builtinIdToTypeSlice [firstUserId]gobType // set in init() after builtins are established181)182 183func idToType(id typeId) gobType {184 if id < 0 || int(id) >= len(idToTypeSlice) {185 return nil186 }187 return idToTypeSlice[id]188}189 190func builtinIdToType(id typeId) gobType {191 if id < 0 || int(id) >= len(builtinIdToTypeSlice) {192 return nil193 }194 return builtinIdToTypeSlice[id]195}196 197func setTypeId(typ gobType) {198 // When building recursive types, someone may get there before us.199 if typ.id() != 0 {200 return201 }202 nextId := typeId(len(idToTypeSlice))203 typ.setId(nextId)204 idToTypeSlice = append(idToTypeSlice, typ)205}206 207func (t typeId) gobType() gobType {208 if t == 0 {209 return nil210 }211 return idToType(t)212}213 214// string returns the string representation of the type associated with the typeId.215func (t typeId) string() string {216 if t.gobType() == nil {217 return "<nil>"218 }219 return t.gobType().string()220}221 222// Name returns the name of the type associated with the typeId.223func (t typeId) name() string {224 if t.gobType() == nil {225 return "<nil>"226 }227 return t.gobType().name()228}229 230// CommonType holds elements of all types.231// It is a historical artifact, kept for binary compatibility and exported232// only for the benefit of the package's encoding of type descriptors. It is233// not intended for direct use by clients.234type CommonType struct {235 Name string236 Id typeId237}238 239func (t *CommonType) id() typeId { return t.Id }240 241func (t *CommonType) setId(id typeId) { t.Id = id }242 243func (t *CommonType) string() string { return t.Name }244 245func (t *CommonType) safeString(seen map[typeId]bool) string {246 return t.Name247}248 249func (t *CommonType) name() string { return t.Name }250 251// Create and check predefined types252// The string for tBytes is "bytes" not "[]byte" to signify its specialness.253 254var (255 // Primordial types, needed during initialization.256 // Always passed as pointers so the interface{} type257 // goes through without losing its interfaceness.258 tBool = bootstrapType("bool", (*bool)(nil))259 tInt = bootstrapType("int", (*int)(nil))260 tUint = bootstrapType("uint", (*uint)(nil))261 tFloat = bootstrapType("float", (*float64)(nil))262 tBytes = bootstrapType("bytes", (*[]byte)(nil))263 tString = bootstrapType("string", (*string)(nil))264 tComplex = bootstrapType("complex", (*complex128)(nil))265 tInterface = bootstrapType("interface", (*any)(nil))266 // Reserve some Ids for compatible expansion267 tReserved7 = bootstrapType("_reserved1", (*struct{ r7 int })(nil))268 tReserved6 = bootstrapType("_reserved1", (*struct{ r6 int })(nil))269 tReserved5 = bootstrapType("_reserved1", (*struct{ r5 int })(nil))270 tReserved4 = bootstrapType("_reserved1", (*struct{ r4 int })(nil))271 tReserved3 = bootstrapType("_reserved1", (*struct{ r3 int })(nil))272 tReserved2 = bootstrapType("_reserved1", (*struct{ r2 int })(nil))273 tReserved1 = bootstrapType("_reserved1", (*struct{ r1 int })(nil))274)275 276// Predefined because it's needed by the Decoder277var tWireType = mustGetTypeInfo(wireTypeType).id278var wireTypeUserInfo *userTypeInfo // userTypeInfo of wireType279 280func init() {281 // Some magic numbers to make sure there are no surprises.282 checkId(16, tWireType)283 checkId(17, mustGetTypeInfo(reflect.TypeFor[arrayType]()).id)284 checkId(18, mustGetTypeInfo(reflect.TypeFor[CommonType]()).id)285 checkId(19, mustGetTypeInfo(reflect.TypeFor[sliceType]()).id)286 checkId(20, mustGetTypeInfo(reflect.TypeFor[structType]()).id)287 checkId(21, mustGetTypeInfo(reflect.TypeFor[fieldType]()).id)288 checkId(23, mustGetTypeInfo(reflect.TypeFor[mapType]()).id)289 290 copy(builtinIdToTypeSlice[:], idToTypeSlice)291 292 // Move the id space upwards to allow for growth in the predefined world293 // without breaking existing files.294 if nextId := len(idToTypeSlice); nextId > firstUserId {295 panic(fmt.Sprintln("nextId too large:", nextId))296 }297 idToTypeSlice = idToTypeSlice[:firstUserId]298 registerBasics()299 wireTypeUserInfo = userType(wireTypeType)300}301 302// Array type303type arrayType struct {304 CommonType305 Elem typeId306 Len int307}308 309func newArrayType(name string) *arrayType {310 a := &arrayType{CommonType{Name: name}, 0, 0}311 return a312}313 314func (a *arrayType) init(elem gobType, len int) {315 // Set our type id before evaluating the element's, in case it's our own.316 setTypeId(a)317 a.Elem = elem.id()318 a.Len = len319}320 321func (a *arrayType) safeString(seen map[typeId]bool) string {322 if seen[a.Id] {323 return a.Name324 }325 seen[a.Id] = true326 return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))327}328 329func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }330 331// GobEncoder type (something that implements the GobEncoder interface)332type gobEncoderType struct {333 CommonType334}335 336func newGobEncoderType(name string) *gobEncoderType {337 g := &gobEncoderType{CommonType{Name: name}}338 setTypeId(g)339 return g340}341 342func (g *gobEncoderType) safeString(seen map[typeId]bool) string {343 return g.Name344}345 346func (g *gobEncoderType) string() string { return g.Name }347 348// Map type349type mapType struct {350 CommonType351 Key typeId352 Elem typeId353}354 355func newMapType(name string) *mapType {356 m := &mapType{CommonType{Name: name}, 0, 0}357 return m358}359 360func (m *mapType) init(key, elem gobType) {361 // Set our type id before evaluating the element's, in case it's our own.362 setTypeId(m)363 m.Key = key.id()364 m.Elem = elem.id()365}366 367func (m *mapType) safeString(seen map[typeId]bool) string {368 if seen[m.Id] {369 return m.Name370 }371 seen[m.Id] = true372 key := m.Key.gobType().safeString(seen)373 elem := m.Elem.gobType().safeString(seen)374 return fmt.Sprintf("map[%s]%s", key, elem)375}376 377func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }378 379// Slice type380type sliceType struct {381 CommonType382 Elem typeId383}384 385func newSliceType(name string) *sliceType {386 s := &sliceType{CommonType{Name: name}, 0}387 return s388}389 390func (s *sliceType) init(elem gobType) {391 // Set our type id before evaluating the element's, in case it's our own.392 setTypeId(s)393 // See the comments about ids in newTypeObject. Only slices and394 // structs have mutual recursion.395 if elem.id() == 0 {396 setTypeId(elem)397 }398 s.Elem = elem.id()399}400 401func (s *sliceType) safeString(seen map[typeId]bool) string {402 if seen[s.Id] {403 return s.Name404 }405 seen[s.Id] = true406 return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))407}408 409func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }410 411// Struct type412type fieldType struct {413 Name string414 Id typeId415}416 417type structType struct {418 CommonType419 Field []fieldType420}421 422func (s *structType) safeString(seen map[typeId]bool) string {423 if s == nil {424 return "<nil>"425 }426 if _, ok := seen[s.Id]; ok {427 return s.Name428 }429 seen[s.Id] = true430 str := s.Name + " = struct { "431 for _, f := range s.Field {432 str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))433 }434 str += "}"435 return str436}437 438func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }439 440func newStructType(name string) *structType {441 s := &structType{CommonType{Name: name}, nil}442 // For historical reasons we set the id here rather than init.443 // See the comment in newTypeObject for details.444 setTypeId(s)445 return s446}447 448// newTypeObject allocates a gobType for the reflection type rt.449// Unless ut represents a GobEncoder, rt should be the base type450// of ut.451// This is only called from the encoding side. The decoding side452// works through typeIds and userTypeInfos alone.453func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {454 // Does this type implement GobEncoder?455 if ut.externalEnc != 0 {456 return newGobEncoderType(name), nil457 }458 var err error459 var type0, type1 gobType460 defer func() {461 if err != nil {462 delete(types, rt)463 }464 }()465 // Install the top-level type before the subtypes (e.g. struct before466 // fields) so recursive types can be constructed safely.467 switch t := rt; t.Kind() {468 // All basic types are easy: they are predefined.469 case reflect.Bool:470 return tBool.gobType(), nil471 472 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:473 return tInt.gobType(), nil474 475 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:476 return tUint.gobType(), nil477 478 case reflect.Float32, reflect.Float64:479 return tFloat.gobType(), nil480 481 case reflect.Complex64, reflect.Complex128:482 return tComplex.gobType(), nil483 484 case reflect.String:485 return tString.gobType(), nil486 487 case reflect.Interface:488 return tInterface.gobType(), nil489 490 case reflect.Array:491 at := newArrayType(name)492 types[rt] = at493 type0, err = getBaseType("", t.Elem())494 if err != nil {495 return nil, err496 }497 // Historical aside:498 // For arrays, maps, and slices, we set the type id after the elements499 // are constructed. This is to retain the order of type id allocation after500 // a fix made to handle recursive types, which changed the order in501 // which types are built. Delaying the setting in this way preserves502 // type ids while allowing recursive types to be described. Structs,503 // done below, were already handling recursion correctly so they504 // assign the top-level id before those of the field.505 at.init(type0, t.Len())506 return at, nil507 508 case reflect.Map:509 mt := newMapType(name)510 types[rt] = mt511 type0, err = getBaseType("", t.Key())512 if err != nil {513 return nil, err514 }515 type1, err = getBaseType("", t.Elem())516 if err != nil {517 return nil, err518 }519 mt.init(type0, type1)520 return mt, nil521 522 case reflect.Slice:523 // []byte == []uint8 is a special case524 if t.Elem().Kind() == reflect.Uint8 {525 return tBytes.gobType(), nil526 }527 st := newSliceType(name)528 types[rt] = st529 type0, err = getBaseType(t.Elem().Name(), t.Elem())530 if err != nil {531 return nil, err532 }533 st.init(type0)534 return st, nil535 536 case reflect.Struct:537 st := newStructType(name)538 types[rt] = st539 idToTypeSlice[st.id()] = st540 for i := 0; i < t.NumField(); i++ {541 f := t.Field(i)542 if !isSent(&f) {543 continue544 }545 typ := userType(f.Type).base546 tname := typ.Name()547 if tname == "" {548 t := userType(f.Type).base549 tname = t.String()550 }551 gt, err := getBaseType(tname, f.Type)552 if err != nil {553 return nil, err554 }555 // Some mutually recursive types can cause us to be here while556 // still defining the element. Fix the element type id here.557 // We could do this more neatly by setting the id at the start of558 // building every type, but that would break binary compatibility.559 if gt.id() == 0 {560 setTypeId(gt)561 }562 st.Field = append(st.Field, fieldType{f.Name, gt.id()})563 }564 return st, nil565 566 default:567 return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String())568 }569}570 571// isExported reports whether this is an exported - upper case - name.572func isExported(name string) bool {573 rune, _ := utf8.DecodeRuneInString(name)574 return unicode.IsUpper(rune)575}576 577// isSent reports whether this struct field is to be transmitted.578// It will be transmitted only if it is exported and not a chan or func field579// or pointer to chan or func.580func isSent(field *reflect.StructField) bool {581 if !isExported(field.Name) {582 return false583 }584 // If the field is a chan or func or pointer thereto, don't send it.585 // That is, treat it like an unexported field.586 typ := field.Type587 for typ.Kind() == reflect.Pointer {588 typ = typ.Elem()589 }590 if typ.Kind() == reflect.Chan || typ.Kind() == reflect.Func {591 return false592 }593 594 return true595}596 597// getBaseType returns the Gob type describing the given reflect.Type's base type.598// typeLock must be held.599func getBaseType(name string, rt reflect.Type) (gobType, error) {600 ut := userType(rt)601 return getType(name, ut, ut.base)602}603 604// getType returns the Gob type describing the given reflect.Type.605// Should be called only when handling GobEncoders/Decoders,606// which may be pointers. All other types are handled through the607// base type, never a pointer.608// typeLock must be held.609func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {610 typ, present := types[rt]611 if present {612 return typ, nil613 }614 typ, err := newTypeObject(name, ut, rt)615 if err == nil {616 types[rt] = typ617 }618 return typ, err619}620 621func checkId(want, got typeId) {622 if want != got {623 fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))624 panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())625 }626}627 628// used for building the basic types; called only from init(). the incoming629// interface always refers to a pointer.630func bootstrapType(name string, e any) typeId {631 rt := reflect.TypeOf(e).Elem()632 _, present := types[rt]633 if present {634 panic("bootstrap type already present: " + name + ", " + rt.String())635 }636 typ := &CommonType{Name: name}637 types[rt] = typ638 setTypeId(typ)639 return typ.id()640}641 642// Representation of the information we send and receive about this type.643// Each value we send is preceded by its type definition: an encoded int.644// However, the very first time we send the value, we first send the pair645// (-id, wireType).646// For bootstrapping purposes, we assume that the recipient knows how647// to decode a wireType; it is exactly the wireType struct here, interpreted648// using the gob rules for sending a structure, except that we assume the649// ids for wireType and structType etc. are known. The relevant pieces650// are built in encode.go's init() function.651// To maintain binary compatibility, if you extend this type, always put652// the new fields last.653type wireType struct {654 ArrayT *arrayType655 SliceT *sliceType656 StructT *structType657 MapT *mapType658 GobEncoderT *gobEncoderType659 BinaryMarshalerT *gobEncoderType660 TextMarshalerT *gobEncoderType661}662 663func (w *wireType) string() string {664 const unknown = "unknown type"665 if w == nil {666 return unknown667 }668 switch {669 case w.ArrayT != nil:670 return w.ArrayT.Name671 case w.SliceT != nil:672 return w.SliceT.Name673 case w.StructT != nil:674 return w.StructT.Name675 case w.MapT != nil:676 return w.MapT.Name677 case w.GobEncoderT != nil:678 return w.GobEncoderT.Name679 case w.BinaryMarshalerT != nil:680 return w.BinaryMarshalerT.Name681 case w.TextMarshalerT != nil:682 return w.TextMarshalerT.Name683 }684 return unknown685}686 687type typeInfo struct {688 id typeId689 encInit sync.Mutex // protects creation of encoder690 encoder atomic.Pointer[encEngine]691 wire wireType692}693 694// typeInfoMap is an atomic pointer to map[reflect.Type]*typeInfo.695// It's updated copy-on-write. Readers just do an atomic load696// to get the current version of the map. Writers make a full copy of697// the map and atomically update the pointer to point to the new map.698// Under heavy read contention, this is significantly faster than a map699// protected by a mutex.700var typeInfoMap atomic.Value701 702// typeInfoMapInit is used instead of typeInfoMap during init time,703// as types are registered sequentially during init and we can save704// the overhead of making map copies.705// It is saved to typeInfoMap and set to nil before init finishes.706var typeInfoMapInit = make(map[reflect.Type]*typeInfo, 16)707 708func lookupTypeInfo(rt reflect.Type) *typeInfo {709 if m := typeInfoMapInit; m != nil {710 return m[rt]711 }712 m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo)713 return m[rt]714}715 716func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {717 rt := ut.base718 if ut.externalEnc != 0 {719 // We want the user type, not the base type.720 rt = ut.user721 }722 if info := lookupTypeInfo(rt); info != nil {723 return info, nil724 }725 return buildTypeInfo(ut, rt)726}727 728// buildTypeInfo constructs the type information for the type729// and stores it in the type info map.730func buildTypeInfo(ut *userTypeInfo, rt reflect.Type) (*typeInfo, error) {731 typeLock.Lock()732 defer typeLock.Unlock()733 734 if info := lookupTypeInfo(rt); info != nil {735 return info, nil736 }737 738 gt, err := getBaseType(rt.Name(), rt)739 if err != nil {740 return nil, err741 }742 info := &typeInfo{id: gt.id()}743 744 if ut.externalEnc != 0 {745 userType, err := getType(rt.Name(), ut, rt)746 if err != nil {747 return nil, err748 }749 gt := userType.id().gobType().(*gobEncoderType)750 switch ut.externalEnc {751 case xGob:752 info.wire.GobEncoderT = gt753 case xBinary:754 info.wire.BinaryMarshalerT = gt755 case xText:756 info.wire.TextMarshalerT = gt757 }758 rt = ut.user759 } else {760 t := info.id.gobType()761 switch typ := rt; typ.Kind() {762 case reflect.Array:763 info.wire.ArrayT = t.(*arrayType)764 case reflect.Map:765 info.wire.MapT = t.(*mapType)766 case reflect.Slice:767 // []byte == []uint8 is a special case handled separately768 if typ.Elem().Kind() != reflect.Uint8 {769 info.wire.SliceT = t.(*sliceType)770 }771 case reflect.Struct:772 info.wire.StructT = t.(*structType)773 }774 }775 776 if m := typeInfoMapInit; m != nil {777 m[rt] = info778 return info, nil779 }780 781 // Create new map with old contents plus new entry.782 m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo)783 newm := maps.Clone(m)784 newm[rt] = info785 typeInfoMap.Store(newm)786 return info, nil787}788 789// Called only when a panic is acceptable and unexpected.790func mustGetTypeInfo(rt reflect.Type) *typeInfo {791 t, err := getTypeInfo(userType(rt))792 if err != nil {793 panic("getTypeInfo: " + err.Error())794 }795 return t796}797 798// GobEncoder is the interface describing data that provides its own799// representation for encoding values for transmission to a GobDecoder.800// A type that implements GobEncoder and GobDecoder has complete801// control over the representation of its data and may therefore802// contain things such as private fields, channels, and functions,803// which are not usually transmissible in gob streams.804//805// Note: Since gobs can be stored permanently, it is good design806// to guarantee the encoding used by a GobEncoder is stable as the807// software evolves. For instance, it might make sense for GobEncode808// to include a version number in the encoding.809type GobEncoder interface {810 // GobEncode returns a byte slice representing the encoding of the811 // receiver for transmission to a GobDecoder, usually of the same812 // concrete type.813 GobEncode() ([]byte, error)814}815 816// GobDecoder is the interface describing data that provides its own817// routine for decoding transmitted values sent by a GobEncoder.818type GobDecoder interface {819 // GobDecode overwrites the receiver, which must be a pointer,820 // with the value represented by the byte slice, which was written821 // by GobEncode, usually for the same concrete type.822 GobDecode([]byte) error823}824 825var (826 nameToConcreteType sync.Map // map[string]reflect.Type827 concreteTypeToName sync.Map // map[reflect.Type]string828)829 830// RegisterName is like [Register] but uses the provided name rather than the831// type's default.832func RegisterName(name string, value any) {833 if name == "" {834 // reserved for nil835 panic("attempt to register empty name")836 }837 838 ut := userType(reflect.TypeOf(value))839 840 // Check for incompatible duplicates. The name must refer to the841 // same user type, and vice versa.842 843 // Store the name and type provided by the user....844 if t, dup := nameToConcreteType.LoadOrStore(name, reflect.TypeOf(value)); dup && t != ut.user {845 panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", name, t, ut.user))846 }847 848 // but the flattened type in the type table, since that's what decode needs.849 if n, dup := concreteTypeToName.LoadOrStore(ut.base, name); dup && n != name {850 nameToConcreteType.Delete(name)851 panic(fmt.Sprintf("gob: registering duplicate names for %s: %q != %q", ut.user, n, name))852 }853}854 855// Register records a type, identified by a value for that type, under its856// internal type name. That name will identify the concrete type of a value857// sent or received as an interface variable. Only types that will be858// transferred as implementations of interface values need to be registered.859// Expecting to be used only during initialization, it panics if the mapping860// between types and names is not a bijection.861func Register(value any) {862 // Default to printed representation for unnamed types863 rt := reflect.TypeOf(value)864 name := rt.String()865 866 // But for named types (or pointers to them), qualify with import path (but see inner comment).867 // Dereference one pointer looking for a named type.868 star := ""869 if rt.Name() == "" {870 if pt := rt; pt.Kind() == reflect.Pointer {871 star = "*"872 // NOTE: The following line should be rt = pt.Elem() to implement873 // what the comment above claims, but fixing it would break compatibility874 // with existing gobs.875 //876 // Given package p imported as "full/p" with these definitions:877 // package p878 // type T1 struct { ... }879 // this table shows the intended and actual strings used by gob to880 // name the types:881 //882 // Type Correct string Actual string883 //884 // T1 full/p.T1 full/p.T1885 // *T1 *full/p.T1 *p.T1886 //887 // The missing full path cannot be fixed without breaking existing gob decoders.888 rt = pt889 }890 }891 if rt.Name() != "" {892 if rt.PkgPath() == "" {893 name = star + rt.Name()894 } else {895 name = star + rt.PkgPath() + "." + rt.Name()896 }897 }898 899 RegisterName(name, value)900}901 902func registerBasics() {903 Register(int(0))904 Register(int8(0))905 Register(int16(0))906 Register(int32(0))907 Register(int64(0))908 Register(uint(0))909 Register(uint8(0))910 Register(uint16(0))911 Register(uint32(0))912 Register(uint64(0))913 Register(float32(0))914 Register(float64(0))915 Register(complex64(0i))916 Register(complex128(0i))917 Register(uintptr(0))918 Register(false)919 Register("")920 Register([]byte(nil))921 Register([]int(nil))922 Register([]int8(nil))923 Register([]int16(nil))924 Register([]int32(nil))925 Register([]int64(nil))926 Register([]uint(nil))927 Register([]uint8(nil))928 Register([]uint16(nil))929 Register([]uint32(nil))930 Register([]uint64(nil))931 Register([]float32(nil))932 Register([]float64(nil))933 Register([]complex64(nil))934 Register([]complex128(nil))935 Register([]uintptr(nil))936 Register([]bool(nil))937 Register([]string(nil))938}939 940func init() {941 typeInfoMap.Store(typeInfoMapInit)942 typeInfoMapInit = nil943}944 