mirror of
				https://github.com/zhufuyi/sponge.git
				synced 2025-10-31 20:42:50 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package encoding
 | |
| 
 | |
| import (
 | |
| 	"encoding"
 | |
| 	"errors"
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// ErrNotAPointer .
 | |
| 	ErrNotAPointer = errors.New("v argument must be a pointer")
 | |
| )
 | |
| 
 | |
| // Codec defines the interface gRPC uses to encode and decode messages.  Note
 | |
| // that implementations of this interface must be thread safe; a Codec's
 | |
| // methods can be called from concurrent goroutines.
 | |
| type Codec interface {
 | |
| 	// Marshal returns the wire format of v.
 | |
| 	Marshal(v interface{}) ([]byte, error)
 | |
| 	// Unmarshal parses the wire format into v.
 | |
| 	Unmarshal(data []byte, v interface{}) error
 | |
| 	// Name returns the name of the Codec implementation. The returned string
 | |
| 	// will be used as part of content type in transmission.  The result must be
 | |
| 	// static; the result cannot change between calls.
 | |
| 	Name() string
 | |
| }
 | |
| 
 | |
| var registeredCodecs = make(map[string]Codec)
 | |
| 
 | |
| // RegisterCodec registers the provided Codec for use with all transport clients and
 | |
| // servers.
 | |
| //
 | |
| // The Codec will be stored and looked up by result of its Name() method, which
 | |
| // should match the content-subtype of the encoding handled by the Codec.  This
 | |
| // is case-insensitive, and is stored and looked up as lowercase.  If the
 | |
| // result of calling Name() is an empty string, RegisterCodec will panic. See
 | |
| // Content-Type on
 | |
| // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
 | |
| // more details.
 | |
| //
 | |
| // NOTE: this function must only be called during initialization time (i.e. in
 | |
| // an init() function), and is not thread-safe.  If multiple Compressors are
 | |
| // registered with the same name, the one registered last will take effect.
 | |
| func RegisterCodec(codec Codec) {
 | |
| 	if codec == nil {
 | |
| 		panic("cannot register a nil Codec")
 | |
| 	}
 | |
| 	if codec.Name() == "" {
 | |
| 		panic("cannot register Codec with empty string result for Name()")
 | |
| 	}
 | |
| 	contentSubtype := strings.ToLower(codec.Name())
 | |
| 	registeredCodecs[contentSubtype] = codec
 | |
| }
 | |
| 
 | |
| // GetCodec gets a registered Codec by content-subtype, or nil if no Codec is
 | |
| // registered for the content-subtype.
 | |
| //
 | |
| // The content-subtype is expected to be lowercase.
 | |
| func GetCodec(contentSubtype string) Codec {
 | |
| 	return registeredCodecs[contentSubtype]
 | |
| }
 | |
| 
 | |
| // Encoding 编码接口定义
 | |
| type Encoding interface {
 | |
| 	Marshal(v interface{}) ([]byte, error)
 | |
| 	Unmarshal(data []byte, v interface{}) error
 | |
| }
 | |
| 
 | |
| // Marshal encode data
 | |
| func Marshal(e Encoding, v interface{}) (data []byte, err error) {
 | |
| 	if !isPointer(v) {
 | |
| 		return data, ErrNotAPointer
 | |
| 	}
 | |
| 	bm, ok := v.(encoding.BinaryMarshaler)
 | |
| 	if ok && e == nil {
 | |
| 		data, err = bm.MarshalBinary()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	data, err = e.Marshal(v)
 | |
| 	if err == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	if ok {
 | |
| 		data, err = bm.MarshalBinary()
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Unmarshal decode data
 | |
| func Unmarshal(e Encoding, data []byte, v interface{}) (err error) {
 | |
| 	if !isPointer(v) {
 | |
| 		return ErrNotAPointer
 | |
| 	}
 | |
| 	bm, ok := v.(encoding.BinaryUnmarshaler)
 | |
| 	if ok && e == nil {
 | |
| 		err = bm.UnmarshalBinary(data)
 | |
| 		return err
 | |
| 	}
 | |
| 	err = e.Unmarshal(data, v)
 | |
| 	if err == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	if ok {
 | |
| 		return bm.UnmarshalBinary(data)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func isPointer(data interface{}) bool {
 | |
| 	switch reflect.ValueOf(data).Kind() {
 | |
| 	case reflect.Ptr, reflect.Interface:
 | |
| 		return true
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| }
 | 
