codec.go raw

   1  /*
   2   *
   3   * Copyright 2014 gRPC authors.
   4   *
   5   * Licensed under the Apache License, Version 2.0 (the "License");
   6   * you may not use this file except in compliance with the License.
   7   * You may obtain a copy of the License at
   8   *
   9   *     http://www.apache.org/licenses/LICENSE-2.0
  10   *
  11   * Unless required by applicable law or agreed to in writing, software
  12   * distributed under the License is distributed on an "AS IS" BASIS,
  13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14   * See the License for the specific language governing permissions and
  15   * limitations under the License.
  16   *
  17   */
  18  
  19  package grpc
  20  
  21  import (
  22  	"google.golang.org/grpc/encoding"
  23  	_ "google.golang.org/grpc/encoding/proto" // to register the Codec for "proto"
  24  	"google.golang.org/grpc/mem"
  25  )
  26  
  27  // baseCodec captures the new encoding.CodecV2 interface without the Name
  28  // function, allowing it to be implemented by older Codec and encoding.Codec
  29  // implementations. The omitted Name function is only needed for the register in
  30  // the encoding package and is not part of the core functionality.
  31  type baseCodec interface {
  32  	Marshal(v any) (mem.BufferSlice, error)
  33  	Unmarshal(data mem.BufferSlice, v any) error
  34  }
  35  
  36  // getCodec returns an encoding.CodecV2 for the codec of the given name (if
  37  // registered). Initially checks the V2 registry with encoding.GetCodecV2 and
  38  // returns the V2 codec if it is registered. Otherwise, it checks the V1 registry
  39  // with encoding.GetCodec and if it is registered wraps it with newCodecV1Bridge
  40  // to turn it into an encoding.CodecV2. Returns nil otherwise.
  41  func getCodec(name string) encoding.CodecV2 {
  42  	if codecV1 := encoding.GetCodec(name); codecV1 != nil {
  43  		return newCodecV1Bridge(codecV1)
  44  	}
  45  
  46  	return encoding.GetCodecV2(name)
  47  }
  48  
  49  func newCodecV0Bridge(c Codec) baseCodec {
  50  	return codecV0Bridge{codec: c}
  51  }
  52  
  53  func newCodecV1Bridge(c encoding.Codec) encoding.CodecV2 {
  54  	return codecV1Bridge{
  55  		codecV0Bridge: codecV0Bridge{codec: c},
  56  		name:          c.Name(),
  57  	}
  58  }
  59  
  60  var _ baseCodec = codecV0Bridge{}
  61  
  62  type codecV0Bridge struct {
  63  	codec interface {
  64  		Marshal(v any) ([]byte, error)
  65  		Unmarshal(data []byte, v any) error
  66  	}
  67  }
  68  
  69  func (c codecV0Bridge) Marshal(v any) (mem.BufferSlice, error) {
  70  	data, err := c.codec.Marshal(v)
  71  	if err != nil {
  72  		return nil, err
  73  	}
  74  	return mem.BufferSlice{mem.SliceBuffer(data)}, nil
  75  }
  76  
  77  func (c codecV0Bridge) Unmarshal(data mem.BufferSlice, v any) (err error) {
  78  	return c.codec.Unmarshal(data.Materialize(), v)
  79  }
  80  
  81  var _ encoding.CodecV2 = codecV1Bridge{}
  82  
  83  type codecV1Bridge struct {
  84  	codecV0Bridge
  85  	name string
  86  }
  87  
  88  func (c codecV1Bridge) Name() string {
  89  	return c.name
  90  }
  91  
  92  // Codec defines the interface gRPC uses to encode and decode messages.
  93  // Note that implementations of this interface must be thread safe;
  94  // a Codec's methods can be called from concurrent goroutines.
  95  //
  96  // Deprecated: use encoding.Codec instead.
  97  type Codec interface {
  98  	// Marshal returns the wire format of v.
  99  	Marshal(v any) ([]byte, error)
 100  	// Unmarshal parses the wire format into v.
 101  	Unmarshal(data []byte, v any) error
 102  	// String returns the name of the Codec implementation.  This is unused by
 103  	// gRPC.
 104  	String() string
 105  }
 106