github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/codec/codec.go (about)

     1  package codec
     2  
     3  import (
     4  	"encoding"
     5  	"errors"
     6  	"reflect"
     7  	"strings"
     8  )
     9  
    10  var (
    11  	// ErrNotAPointer .
    12  	ErrNotAPointer = errors.New("v argument must be a pointer")
    13  )
    14  
    15  // Codec defines the interface gRPC uses to encode and decode messages.  Note
    16  // that implementations of this interface must be thread safe; a Codec's
    17  // methods can be called from concurrent goroutines.
    18  type Codec interface {
    19  	// Marshal returns the wire format of v.
    20  	Marshal(v any) ([]byte, error)
    21  	// Unmarshal parses the wire format into v.
    22  	Unmarshal(data []byte, v any) error
    23  	// Name returns the name of the Codec implementation. The returned string
    24  	// will be used as part of content type in transmission.  The result must be
    25  	// static; the result cannot change between calls.
    26  	Name() string
    27  }
    28  
    29  var registeredCodecs = make(map[string]Codec)
    30  
    31  // RegisterCodec registers the provided Codec for use with all transport clients and
    32  // servers.
    33  //
    34  // The Codec will be stored and looked up by result of its Name() method, which
    35  // should match the content-subtype of the encoding handled by the Codec.  This
    36  // is case-insensitive, and is stored and looked up as lowercase.  If the
    37  // result of calling Name() is an empty string, RegisterCodec will panic. See
    38  // Content-Type on
    39  // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
    40  // more details.
    41  //
    42  // NOTE: this function must only be called during initialization time (i.e. in
    43  // an init() function), and is not thread-safe.  If multiple Compressors are
    44  // registered with the same name, the one registered last will take effect.
    45  func RegisterCodec(codec Codec) {
    46  	if codec == nil {
    47  		panic("cannot register a nil Codec")
    48  	}
    49  	if codec.Name() == "" {
    50  		panic("cannot register Codec with empty string result for Name()")
    51  	}
    52  	contentSubtype := strings.ToLower(codec.Name())
    53  	registeredCodecs[contentSubtype] = codec
    54  }
    55  
    56  // GetCodec gets a registered Codec by content-subtype, or nil if no Codec is
    57  // registered for the content-subtype.
    58  //
    59  // The content-subtype is expected to be lowercase.
    60  func GetCodec(contentSubtype string) Codec {
    61  	return registeredCodecs[contentSubtype]
    62  }
    63  
    64  // Encoding 编码接口定义
    65  type Encoding interface {
    66  	Marshal(v any) ([]byte, error)
    67  	Unmarshal(data []byte, v any) error
    68  }
    69  
    70  // Marshal encode data
    71  func Marshal(e Encoding, v any) (data []byte, err error) {
    72  	if !isPointer(v) {
    73  		return data, ErrNotAPointer
    74  	}
    75  	bm, ok := v.(encoding.BinaryMarshaler)
    76  	if ok && e == nil {
    77  		data, err = bm.MarshalBinary()
    78  		return
    79  	}
    80  
    81  	data, err = e.Marshal(v)
    82  	if err == nil {
    83  		return
    84  	}
    85  	if ok {
    86  		data, err = bm.MarshalBinary()
    87  	}
    88  
    89  	return
    90  }
    91  
    92  // Unmarshal decode data
    93  func Unmarshal(e Encoding, data []byte, v any) (err error) {
    94  	if !isPointer(v) {
    95  		return ErrNotAPointer
    96  	}
    97  	bm, ok := v.(encoding.BinaryUnmarshaler)
    98  	if ok && e == nil {
    99  		err = bm.UnmarshalBinary(data)
   100  		return err
   101  	}
   102  	err = e.Unmarshal(data, v)
   103  	if err == nil {
   104  		return
   105  	}
   106  	if ok {
   107  		return bm.UnmarshalBinary(data)
   108  	}
   109  	return
   110  }
   111  
   112  func isPointer(data any) bool {
   113  	switch reflect.ValueOf(data).Kind() {
   114  	case reflect.Ptr, reflect.Interface:
   115  		return true
   116  	default:
   117  		return false
   118  	}
   119  }