Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
type.go944 linesDownload Raw Back to gob
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 
codekingpro/portable-devtools · Team Ai