// 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 gobimport ()// tooBig provides a sanity check for sizes; used in several places. Upper limit// of is 1GB on 32-bit systems, 8GB on 64-bit, allowing room to grow a little// without overflow.const tooBig = (1 << 30) << (^uint(0) >> 62)// A Decoder manages the receipt of type and data information read from the// remote side of a connection. It is safe for concurrent use by multiple// goroutines.//// The Decoder does only basic sanity checking on decoded input sizes,// and its limits are not configurable. Take caution when decoding gob data// from untrusted sources.typeDecoderstruct { mutex sync.Mutex// each item must be received atomically r io.Reader// source of the data buf decBuffer// buffer for more efficient i/o from r wireType map[typeId]*wireType// map from remote ID to local description decoderCache map[reflect.Type]map[typeId]**decEngine// cache of compiled engines ignorerCache map[typeId]**decEngine// ditto for ignored objects freeList *decoderState// list of free decoderStates; avoids reallocation countBuf []byte// used for decoding integers while parsing messages err error}// NewDecoder returns a new decoder that reads from the io.Reader.// If r does not also implement io.ByteReader, it will be wrapped in a// bufio.Reader.func ( io.Reader) *Decoder { := new(Decoder)// We use the ability to read bytes as a plausible surrogate for buffering.if , := .(io.ByteReader); ! { = bufio.NewReader() } .r = .wireType = make(map[typeId]*wireType) .decoderCache = make(map[reflect.Type]map[typeId]**decEngine) .ignorerCache = make(map[typeId]**decEngine) .countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytesreturn}// recvType loads the definition of a type.func ( *Decoder) ( typeId) {// Have we already seen this type? That's an errorif < firstUserId || .wireType[] != nil { .err = errors.New("gob: duplicate type received")return }// Type: := new(wireType) .decodeValue(tWireType, reflect.ValueOf())if .err != nil {return }// Remember we've seen this type. .wireType[] = }var errBadCount = errors.New("invalid message length")// recvMessage reads the next count-delimited item from the input. It is the converse// of Encoder.writeMessage. It returns false on EOF or other error reading the message.func ( *Decoder) () bool {// Read a count. , , := decodeUintReader(.r, .countBuf)if != nil { .err = returnfalse }if >= tooBig { .err = errBadCountreturnfalse } .readMessage(int())return .err == nil}// readMessage reads the next nbytes bytes from the input.func ( *Decoder) ( int) {if .buf.Len() != 0 {// The buffer should always be empty now.panic("non-empty decoder buffer") }// Read the datavar []byte , .err = saferio.ReadData(.r, uint64()) .buf.SetBytes()if .err == io.EOF { .err = io.ErrUnexpectedEOF }}// toInt turns an encoded uint64 into an int, according to the marshaling rules.func toInt( uint64) int64 { := int64( >> 1)if &1 != 0 { = ^ }return}func ( *Decoder) () int64 { , , := decodeUintReader(&.buf, .countBuf)if != nil { .err = }returntoInt()}func ( *Decoder) () uint64 { , , := decodeUintReader(&.buf, .countBuf)if != nil { .err = }return}// decodeTypeSequence parses:// TypeSequence//// (TypeDefinition DelimitedTypeDefinition*)?//// and returns the type id of the next value. It returns -1 at// EOF. Upon return, the remainder of dec.buf is the value to be// decoded. If this is an interface value, it can be ignored by// resetting that buffer.func ( *Decoder) ( bool) typeId { := truefor .err == nil {if .buf.Len() == 0 {if !.recvMessage() {// We can only return io.EOF if the input was empty. // If we read one or more type spec messages, // require a data item message to follow. // If we hit an EOF before that, then give ErrUnexpectedEOF.if ! && .err == io.EOF { .err = io.ErrUnexpectedEOF }break } }// Receive a type id. := typeId(.nextInt())if >= 0 {// Value follows.return }// Type definition for (-id) follows. .recvType(-)if .err != nil {break }// When decoding an interface, after a type there may be a // DelimitedValue still in the buffer. Skip its count. // (Alternatively, the buffer is empty and the byte count // will be absorbed by recvMessage.)if .buf.Len() > 0 {if ! { .err = errors.New("extra data in buffer")break } .nextUint() } = false }return -1}// Decode reads the next value from the input stream and stores// it in the data represented by the empty interface value.// If e is nil, the value will be discarded. Otherwise,// the value underlying e must be a pointer to the// correct type for the next data item received.// If the input is at EOF, Decode returns io.EOF and// does not modify e.func ( *Decoder) ( any) error {if == nil {return .DecodeValue(reflect.Value{}) } := reflect.ValueOf()// If e represents a value as opposed to a pointer, the answer won't // get back to the caller. Make sure it's a pointer.if .Type().Kind() != reflect.Pointer { .err = errors.New("gob: attempt to decode into a non-pointer")return .err }return .DecodeValue()}// DecodeValue reads the next value from the input stream.// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.// Otherwise, it stores the value into v. In that case, v must represent// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())// If the input is at EOF, DecodeValue returns io.EOF and// does not modify v.func ( *Decoder) ( reflect.Value) error {if .IsValid() {if .Kind() == reflect.Pointer && !.IsNil() {// That's okay, we'll store through the pointer. } elseif !.CanSet() {returnerrors.New("gob: DecodeValue of unassignable value") } }// Make sure we're single-threaded through here. .mutex.Lock()defer .mutex.Unlock() .buf.Reset() // In case data lingers from previous invocation. .err = nil := .decodeTypeSequence(false)if .err == nil { .decodeValue(, ) }return .err}// If debug.go is compiled into the program, debugFunc prints a human-readable// representation of the gob data read from r by calling that file's Debug function.// Otherwise it is nil.var debugFunc func(io.Reader)
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.