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 } }