codec.go

  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
 19package grpc
 20
 21import (
 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.
 31type 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.
 41func 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
 49func newCodecV0Bridge(c Codec) baseCodec {
 50	return codecV0Bridge{codec: c}
 51}
 52
 53func newCodecV1Bridge(c encoding.Codec) encoding.CodecV2 {
 54	return codecV1Bridge{
 55		codecV0Bridge: codecV0Bridge{codec: c},
 56		name:          c.Name(),
 57	}
 58}
 59
 60var _ baseCodec = codecV0Bridge{}
 61
 62type codecV0Bridge struct {
 63	codec interface {
 64		Marshal(v any) ([]byte, error)
 65		Unmarshal(data []byte, v any) error
 66	}
 67}
 68
 69func (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
 77func (c codecV0Bridge) Unmarshal(data mem.BufferSlice, v any) (err error) {
 78	return c.codec.Unmarshal(data.Materialize(), v)
 79}
 80
 81var _ encoding.CodecV2 = codecV1Bridge{}
 82
 83type codecV1Bridge struct {
 84	codecV0Bridge
 85	name string
 86}
 87
 88func (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.
 97type 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}